context_reaction_block.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <?php
  2. /**
  3. * Expose blocks as context reactions.
  4. */
  5. class context_reaction_block extends context_reaction {
  6. /**
  7. * Options form.
  8. */
  9. function options_form($context) {
  10. // Rebuild the block info cache if necessary.
  11. $this->get_blocks(NULL, NULL, $this->rebuild_needed());
  12. $this->rebuild_needed(FALSE);
  13. $theme_key = variable_get('theme_default', 'garland');
  14. $weight_delta = $this->max_block_weight();
  15. $form = array(
  16. '#tree' => TRUE,
  17. '#theme' => 'context_block_form',
  18. 'max_block_weight' => array(
  19. '#value' => $weight_delta,
  20. '#type' => 'value',
  21. ),
  22. 'state' => array(
  23. '#type' => 'hidden',
  24. '#attributes' => array('class' => 'context-blockform-state'),
  25. ),
  26. );
  27. /**
  28. * Selector.
  29. */
  30. $modules = module_list();
  31. $form['selector'] = array(
  32. '#type' => 'item',
  33. '#tree' => TRUE,
  34. '#prefix' => '<div class="context-blockform-selector">',
  35. '#suffix' => '</div>',
  36. );
  37. foreach ($this->get_blocks() as $block) {
  38. $group = isset($block->context_group) ? $block->context_group : $block->module;
  39. if (!isset($form['selector'][$group])) {
  40. $form['selector'][$group] = array(
  41. '#type' => 'checkboxes',
  42. '#title' => isset($block->context_group) ? $block->context_group : $modules[$block->module],
  43. '#options' => array(),
  44. );
  45. }
  46. $form['selector'][$group]['#options'][$block->bid] = check_plain($block->info);
  47. }
  48. ksort($form['selector']);
  49. /**
  50. * Regions.
  51. */
  52. $form['blocks'] = array(
  53. '#tree' => TRUE,
  54. '#theme' => 'context_block_regions_form',
  55. );
  56. foreach (system_region_list($theme_key, REGIONS_VISIBLE) as $region => $label) {
  57. $form['blocks'][$region] = array(
  58. '#type' => 'item',
  59. '#title' => $label,
  60. '#tree' => TRUE,
  61. );
  62. foreach ($this->get_blocks($region, $context) as $block) {
  63. if (!empty($block->context)) {
  64. $form['blocks'][$region][$block->bid] = array(
  65. '#value' => check_plain($block->info),
  66. '#weight' => $block->weight,
  67. '#type' => 'markup',
  68. '#tree' => TRUE,
  69. 'weight' => array('#type' => 'weight', '#delta' => $weight_delta, '#default_value' => $block->weight),
  70. );
  71. }
  72. }
  73. }
  74. return $form;
  75. }
  76. /**
  77. * Options form submit handler.
  78. */
  79. function options_form_submit($values) {
  80. $blocks = array();
  81. $block_info = $this->get_blocks();
  82. // Retrieve blocks from submitted JSON string.
  83. if (!empty($values['state'])) {
  84. $edited = $this->json_decode($values['state']);
  85. }
  86. else {
  87. $edited = array();
  88. }
  89. foreach ($edited as $region => $block_data) {
  90. foreach ($block_data as $position => $data) {
  91. if (isset($block_info[$data->bid])) {
  92. $blocks[$data->bid] = array(
  93. 'module' => $block_info[$data->bid]->module,
  94. 'delta' => $block_info[$data->bid]->delta,
  95. 'region' => $region,
  96. 'weight' => $data->weight,
  97. );
  98. }
  99. }
  100. }
  101. return array('blocks' => $blocks);
  102. }
  103. /**
  104. * Context editor form for blocks.
  105. */
  106. function editor_form($context) {
  107. $form = array();
  108. drupal_add_library('system', 'ui.droppable');
  109. drupal_add_library('system', 'ui.sortable');
  110. drupal_add_js(drupal_get_path('module', 'context_ui') . '/json2.js');
  111. drupal_add_js(drupal_get_path('module', 'context_ui') . '/theme/filter.js');
  112. drupal_add_js(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.js');
  113. drupal_add_css(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.css');
  114. // We might be called multiple times so use a static to ensure this is set just once.
  115. static $once;
  116. if (!isset($once)) {
  117. $settings = array(
  118. 'path' => drupal_is_front_page() ? base_path() : url($_GET['q']),
  119. 'params' => (object) array_diff_key($_GET, array('q' => '')),
  120. 'scriptPlaceholder' => theme('context_block_script_placeholder', array('text' => '')),
  121. );
  122. drupal_add_js(array('contextBlockEditor' => $settings), 'setting');
  123. $once = TRUE;
  124. }
  125. $form['state'] = array(
  126. '#type' => 'hidden',
  127. '#attributes' => array('class' => array('context-block-editor-state')),
  128. );
  129. $form['browser'] = array(
  130. '#markup' => theme('context_block_browser', array(
  131. 'blocks' => $this->get_blocks(NULL, NULL, $this->rebuild_needed()),
  132. 'context' => $context
  133. )),
  134. );
  135. $this->rebuild_needed(FALSE);
  136. return $form;
  137. }
  138. /**
  139. * Submit handler context editor form.
  140. */
  141. function editor_form_submit(&$context, $values) {
  142. $edited = !empty($values['state']) ? (array) $this->json_decode($values['state']) : array();
  143. $options = array();
  144. // Take the existing context values and remove blocks that belong affected regions.
  145. $affected_regions = array_keys($edited);
  146. if (!empty($context->reactions['block']['blocks'])) {
  147. $options = $context->reactions['block'];
  148. foreach ($options['blocks'] as $key => $block) {
  149. if (in_array($block['region'], $affected_regions)) {
  150. unset($options['blocks'][$key]);
  151. }
  152. }
  153. }
  154. // Iterate through blocks and add in the ones that belong to the context.
  155. foreach ($edited as $region => $blocks) {
  156. foreach ($blocks as $weight => $block) {
  157. if ($block->context === $context->name) {
  158. $split = explode('-', $block->bid);
  159. $options['blocks'][$block->bid] = array(
  160. 'module' => array_shift($split),
  161. 'delta' => implode('-', $split),
  162. 'region' => $region,
  163. 'weight' => $weight,
  164. );
  165. }
  166. }
  167. }
  168. return $options;
  169. }
  170. /**
  171. * Settings form for variables.
  172. */
  173. function settings_form() {
  174. $form = array();
  175. $form['context_reaction_block_all_regions'] = array(
  176. '#title' => t('Show all regions'),
  177. '#type' => 'checkbox',
  178. '#default_value' => variable_get('context_reaction_block_all_regions', FALSE),
  179. '#description' => t('Show all regions including those that are empty. Enable if you are administering your site using the inline editor.')
  180. );
  181. return $form;
  182. }
  183. /**
  184. * Execute.
  185. */
  186. function execute(&$page) {
  187. global $theme;
  188. // The theme system might not yet be initialized. We need $theme.
  189. drupal_theme_initialize();
  190. // If the context_block querystring param is set, switch to AJAX rendering.
  191. // Note that we check the output buffer for any content to ensure that we
  192. // are not in the middle of a PHP template render.
  193. if (isset($_GET['context_block']) && !ob_get_contents()) {
  194. return $this->render_ajax($_GET['context_block']);
  195. }
  196. // Populate all block regions
  197. $all_regions = system_region_list($theme);
  198. // Load all region content assigned via blocks.
  199. foreach (array_keys($all_regions) as $region) {
  200. if ($this->is_enabled_region($region)) {
  201. if ($blocks = $this->block_get_blocks_by_region($region)) {
  202. // Are the blocks already sorted.
  203. $blocks_sorted = TRUE;
  204. // If blocks have already been placed in this region (most likely by
  205. // Block module), then merge in blocks from Context.
  206. if (isset($page[$region])) {
  207. $page[$region] = array_merge($page[$region], $blocks);
  208. // Restore the weights that Block module manufactured
  209. // @see _block_get_renderable_array()
  210. foreach ($page[$region] as &$block) {
  211. if (isset($block['#block']->weight)) {
  212. $block['#weight'] = $block['#block']->weight;
  213. $blocks_sorted = FALSE;
  214. }
  215. }
  216. }
  217. else {
  218. $page[$region] = $blocks;
  219. }
  220. $page[$region]['#sorted'] = $blocks_sorted;
  221. }
  222. }
  223. }
  224. }
  225. /**
  226. * Return a list of enabled regions for which blocks should be built.
  227. * Split out into a separate method for easy overrides in extending classes.
  228. */
  229. protected function is_enabled_region($region) {
  230. global $theme;
  231. $regions = array_keys(system_region_list($theme));
  232. return in_array($region, $regions, TRUE);
  233. }
  234. /**
  235. * Determine whether inline editing requirements are met and that the current
  236. * user may edit.
  237. */
  238. protected function is_editable_region($region, $reset = FALSE) {
  239. // Check requirements.
  240. // Generally speaking, it does not make sense to allow anonymous users to
  241. // edit a context inline. Though it may be possible to save (and restore)
  242. // an edited context to an anonymous user's cookie or session, it's an
  243. // edge case and probably not something we want to encourage anyway.
  244. static $requirements;
  245. if (!isset($requirements) || $reset) {
  246. global $user;
  247. if ($user->uid) {
  248. $requirements = TRUE;
  249. drupal_add_library('system', 'ui.droppable');
  250. drupal_add_library('system', 'ui.sortable');
  251. drupal_add_js(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.js');
  252. drupal_add_css(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.css');
  253. }
  254. else {
  255. $requirements = FALSE;
  256. }
  257. }
  258. // Check that this region is not locked by the theme.
  259. global $theme;
  260. $info = system_get_info('theme', $theme);
  261. if ($info && isset($info['regions_locked']) && in_array($region, $info['regions_locked'])) {
  262. return FALSE;
  263. }
  264. // Check that this region is not hidden
  265. $visible = system_region_list($theme, REGIONS_VISIBLE);
  266. return $requirements && $this->is_enabled_region($region) && isset($visible[$region]);
  267. }
  268. /**
  269. * Add markup for making a block editable.
  270. */
  271. protected function editable_block($block) {
  272. if (!empty($block->content)) {
  273. $block->content = array(
  274. 'content' => $block->content,
  275. 'context' => array('#markup' => "<a id='context-block-{$block->module}-{$block->delta}' class='context-block editable edit-{$block->context}'></a>"),
  276. );
  277. //Contextual links are in the wrong spot in the render array once we've nested them
  278. if (isset($block->content['content']['#contextual_links'])) {
  279. $block->content['#contextual_links'] = $block->content['content']['#contextual_links'];
  280. unset($block->content['content']['#contextual_links']);
  281. }
  282. }
  283. else {
  284. // the block alter in context.module should ensure that blocks are never
  285. // empty if the inline editor is present but in the case that they are,
  286. // warn that editing the context is likely to cause this block to be dropped
  287. drupal_set_message(t('The block with delta @delta from module @module is not compatible with the inline editor and will be dropped from the context containing it if you edit contexts here', array('@delta' => $block->delta, '@module' => $block->module)), 'warning');
  288. }
  289. return $block;
  290. }
  291. /**
  292. * Add markup for making a region editable.
  293. */
  294. protected function editable_region($region, $build) {
  295. if ($this->is_editable_region($region) &&
  296. (!empty($build) ||
  297. variable_get('context_reaction_block_all_regions', FALSE) ||
  298. context_isset('context_ui', 'context_ui_editor_present'))
  299. ) {
  300. global $theme;
  301. $regions = system_region_list($theme);
  302. $name = isset($regions[$region]) ? $regions[$region] : $region;
  303. // The negative weight + sorted will push our region marker to the top of the region
  304. $build['context'] = array(
  305. '#prefix' => "<div class='context-block-region' id='context-block-region-{$region}'>",
  306. '#markup' => "<span class='region-name'>{$name}</span>" .
  307. "<a class='context-ui-add-link'>" . t('Add a block here.') . '</a>',
  308. '#suffix' => '</div>',
  309. '#weight' => -100,
  310. );
  311. $build['#sorted'] = FALSE;
  312. }
  313. return $build;
  314. }
  315. /**
  316. * Get a renderable array of a region containing all enabled blocks.
  317. */
  318. function block_get_blocks_by_region($region) {
  319. module_load_include('module', 'block', 'block');
  320. $build = array();
  321. if ($list = $this->block_list($region)) {
  322. $build = _block_get_renderable_array($list);
  323. }
  324. if ($this->is_editable_region($region)) {
  325. $build = $this->editable_region($region, $build);
  326. }
  327. return $build;
  328. }
  329. /**
  330. * An alternative version of block_list() that provides any context enabled blocks.
  331. */
  332. function block_list($region) {
  333. module_load_include('module', 'block', 'block');
  334. $context_blocks = &drupal_static('context_reaction_block_list');;
  335. $contexts = context_active_contexts();
  336. if (!isset($context_blocks)) {
  337. $info = $this->get_blocks();
  338. $context_blocks = array();
  339. foreach ($contexts as $context) {
  340. $options = $this->fetch_from_context($context);
  341. if (!empty($options['blocks'])) {
  342. foreach ($options['blocks'] as $context_block) {
  343. $bid = "{$context_block['module']}-{$context_block['delta']}";
  344. if (isset($info[$bid])) {
  345. $block = (object) array_merge((array) $info[$bid], $context_block);
  346. $block->context = $context->name;
  347. $block->title = isset($info[$block->bid]->title) ? $info[$block->bid]->title : NULL;
  348. $block->cache = isset($info[$block->bid]->cache) ? $info[$block->bid]->cache : DRUPAL_NO_CACHE;
  349. $context_blocks[$block->region][$block->bid] = $block;
  350. }
  351. }
  352. }
  353. }
  354. $this->is_editable_check($context_blocks);
  355. foreach ($context_blocks as $r => $blocks) {
  356. $context_blocks[$r] = _block_render_blocks($blocks);
  357. // Make blocks editable if allowed.
  358. if ($this->is_editable_region($r)) {
  359. foreach ($context_blocks[$r] as $key => $block) {
  360. $context_blocks[$r][$key] = $this->editable_block($block);
  361. }
  362. }
  363. // Sort blocks.
  364. uasort($context_blocks[$r], array('context_reaction_block', 'block_sort'));
  365. }
  366. }
  367. return isset($context_blocks[$region]) ? $context_blocks[$region] : array();
  368. }
  369. /**
  370. * Determine if there is an active context editor block, and set a flag. We will set a flag so
  371. * that we can make sure that blocks with empty content have some default content. This is
  372. * needed so the save of the context inline editor does not remove the blocks with no content.
  373. */
  374. function is_editable_check($context_blocks) {
  375. foreach ($context_blocks as $r => $blocks) {
  376. if (isset($blocks['context_ui-editor'])) {
  377. $block = $blocks['context_ui-editor'];
  378. // see if the editor is actually enabled, lifted from _block_render_blocks
  379. if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
  380. $array = $cache->data;
  381. }
  382. else {
  383. $array = module_invoke($block->module, 'block_view', $block->delta);
  384. drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
  385. }
  386. if(!empty($array['content'])) {
  387. context_set('context_ui', 'context_ui_editor_present', TRUE);
  388. }
  389. break;
  390. }
  391. }
  392. }
  393. /**
  394. * Generate the safe weight range for a block being added to a region such that
  395. * there are enough potential unique weights to support all blocks.
  396. */
  397. protected function max_block_weight() {
  398. $blocks = $this->get_blocks();
  399. $block_count = 0;
  400. foreach ($blocks as $region => $block_list) {
  401. $block_count += count($block_list);
  402. }
  403. // Add 2 to make sure there's space at either end of the block list
  404. return round(($block_count + 2) / 2);
  405. }
  406. /**
  407. * Check or set whether a rebuild of the block info cache is needed.
  408. */
  409. function rebuild_needed($set = NULL) {
  410. if (isset($set) && $set != variable_get('context_block_rebuild_needed', FALSE)) {
  411. variable_set('context_block_rebuild_needed', $set);
  412. }
  413. return (bool) variable_get('context_block_rebuild_needed', FALSE);
  414. }
  415. /**
  416. * Helper function to generate a list of blocks from a specified region. If provided a context object,
  417. * will generate a full list of blocks for that region distinguishing between system blocks and
  418. * context-provided blocks.
  419. *
  420. * @param $region
  421. * The string identifier for a theme region. e.g. "left"
  422. * @param $context
  423. * A context object.
  424. *
  425. * @return
  426. * A keyed (by "module_delta" convention) array of blocks.
  427. */
  428. function get_blocks($region = NULL, $context = NULL, $reset = FALSE) {
  429. static $block_info;
  430. $theme_key = variable_get('theme_default', 'garland');
  431. if (!isset($block_info) || $reset) {
  432. $block_info = array();
  433. if (!$reset) {
  434. $block_info = context_cache_get('block_info');
  435. }
  436. if (empty($block_info)) {
  437. if (module_exists('block')) {
  438. $block_blocks = _block_rehash($theme_key);
  439. $block_info = array();
  440. // Change from numeric keys to module-delta.
  441. foreach ($block_blocks as $block) {
  442. $block = (object) $block;
  443. unset($block->theme, $block->status, $block->weight, $block->region, $block->custom, $block->visibility, $block->pages);
  444. $block->bid = "{$block->module}-{$block->delta}";
  445. $block_info[$block->bid] = $block;
  446. }
  447. }
  448. else {
  449. $block_info = array();
  450. foreach (module_implements('block_info') as $module) {
  451. $module_blocks = module_invoke($module, 'block_info');
  452. if (!empty($module_blocks)) {
  453. foreach ($module_blocks as $delta => $block) {
  454. $block = (object) $block;
  455. $block->module = $module;
  456. $block->delta = $delta;
  457. $block->bid = "{$block->module}-{$block->delta}";
  458. $block_info[$block->bid] = $block;
  459. }
  460. }
  461. }
  462. }
  463. context_cache_set('block_info', $block_info);
  464. }
  465. // Allow other modules that may declare blocks dynamically to alter
  466. // this list.
  467. drupal_alter('context_block_info', $block_info);
  468. // Gather only region info from the database.
  469. if (module_exists('block')) {
  470. $result = db_select('block')
  471. ->fields('block')
  472. ->condition('theme', $theme_key)
  473. ->execute();
  474. foreach ($result as $row) {
  475. if (isset($block_info["{$row->module}-{$row->delta}"])) {
  476. $block_info["{$row->module}-{$row->delta}"] = (object) array_merge((array) $row, (array) $block_info["{$row->module}-{$row->delta}"]);
  477. unset($block_info["{$row->module}-{$row->delta}"]->status);
  478. unset($block_info["{$row->module}-{$row->delta}"]->visibility);
  479. unset($block_info["{$row->module}-{$row->delta}"]->cache);
  480. }
  481. }
  482. }
  483. }
  484. $blocks = array();
  485. // No region specified, provide all blocks.
  486. if (!isset($region)) {
  487. $blocks = $block_info;
  488. }
  489. // Region specified.
  490. else {
  491. foreach ($block_info as $bid => $block) {
  492. if (isset($block->region) && $block->region == $region) {
  493. $blocks[$bid] = $block;
  494. }
  495. }
  496. }
  497. // Add context blocks if provided.
  498. if (is_object($context) && $options = $this->fetch_from_context($context)) {
  499. if (!empty($options['blocks'])) {
  500. foreach ($options['blocks'] as $block) {
  501. if (
  502. isset($block_info["{$block['module']}-{$block['delta']}"]) && // Block is valid.
  503. (!isset($region) || (!empty($region) && $block['region'] == $region)) // No region specified or regions match.
  504. ) {
  505. $context_block = $block_info["{$block['module']}-{$block['delta']}"];
  506. $context_block->weight = $block['weight'];
  507. $context_block->region = $block['region'];
  508. $context_block->context = !empty($context->name) ? $context->name : 'tempname';
  509. $blocks[$context_block->bid] = $context_block;
  510. }
  511. }
  512. }
  513. uasort($blocks, array('context_reaction_block', 'block_sort'));
  514. }
  515. return $blocks;
  516. }
  517. /**
  518. * Sort callback.
  519. */
  520. static function block_sort($a, $b) {
  521. return ($a->weight - $b->weight);
  522. }
  523. /**
  524. * Compatibility wrapper around json_decode().
  525. */
  526. protected function json_decode($json, $assoc = FALSE) {
  527. // Requires PHP 5.2.
  528. if (function_exists('json_decode')) {
  529. return json_decode($json, $assoc);
  530. }
  531. return context_reaction_block::_json_decode($json);
  532. }
  533. /**
  534. * From http://www.php.net/manual/en/function.json-decode.php#91216
  535. * with modifications for consistency with output of json_decode().
  536. *
  537. * Original author: walidator.info 2009.
  538. */
  539. static function _json_decode($json) {
  540. $comment = FALSE;
  541. $out = '$x = ';
  542. for ($i=0; $i < strlen($json); $i++) {
  543. if (!$comment) {
  544. switch ($json[$i]) {
  545. case '{':
  546. $out .= ' (object) array(';
  547. break;
  548. case '}':
  549. $out .= ')';
  550. break;
  551. case '[':
  552. $out .= ' array(';
  553. break;
  554. case ']':
  555. $out .= ')';
  556. break;
  557. case ':';
  558. $out .= '=>';
  559. break;
  560. default:
  561. $out .= $json[$i];
  562. break;
  563. }
  564. }
  565. else {
  566. $out .= $json[$i];
  567. }
  568. if ($json[$i] == '"') {
  569. $comment = !$comment;
  570. }
  571. }
  572. eval($out . ';');
  573. return $x;
  574. }
  575. /**
  576. * Block renderer for AJAX requests. Triggered when $_GET['context_block']
  577. * is set. See ->execute() for how this is called.
  578. */
  579. function render_ajax($param) {
  580. // Besure the page isn't a 404 or 403.
  581. $headers = drupal_get_http_header();
  582. if (array_key_exists('status', $headers) && ($headers['status'] == "404 Not Found" || $headers['status'] == "403 Forbidden")) {
  583. return;
  584. }
  585. // Set the header right away. This will inform any players in the stack
  586. // that we are in the middle of responding to an AJAX request.
  587. drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
  588. if (strpos($param, ',') !== FALSE) {
  589. list($bid, $context) = explode(',', $param);
  590. list($module, $delta) = explode('-', $bid, 2);
  591. // Check token to make sure user has access to block.
  592. if (empty($_GET['context_token']) || $_GET['context_token'] != drupal_get_token($bid)) {
  593. echo drupal_json_encode(array('status' => 0));
  594. exit;
  595. }
  596. // Ensure $bid is valid.
  597. $info = $this->get_blocks();
  598. if (isset($info[$bid])) {
  599. module_load_include('module', 'block', 'block');
  600. $block = $info[$bid];
  601. $block->title = isset($block->title) ? $block->title : '';
  602. $block->context = $context;
  603. $block->region = '';
  604. $rendered_blocks = _block_render_blocks(array($block)); // For E_STRICT warning
  605. $block = array_shift($rendered_blocks);
  606. if (empty($block->content['#markup'])) {
  607. $block->content['#markup'] = "<div class='context-block-empty'>" . t('This block appears empty when displayed on this page.') . "</div>";
  608. }
  609. $block = $this->editable_block($block);
  610. $renderable_block = _block_get_renderable_array(array($block)); // For E_STRICT warning
  611. echo drupal_json_encode(array(
  612. 'status' => 1,
  613. 'block' => drupal_render($renderable_block),
  614. ));
  615. drupal_exit();
  616. }
  617. }
  618. echo drupal_json_encode(array('status' => 0));
  619. drupal_exit();
  620. }
  621. }