context_ui.module 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. /**
  3. * Implementation of hook_ctools_plugin_directory().
  4. */
  5. function context_ui_ctools_plugin_directory($module, $plugin) {
  6. if ($module == 'ctools' && $plugin == 'export_ui') {
  7. return 'export_ui';
  8. }
  9. }
  10. /**
  11. * Implementation of hook_theme().
  12. */
  13. function context_ui_theme() {
  14. $items = array();
  15. $items['context_ui_form'] = array(
  16. 'render element' => 'form',
  17. 'path' => drupal_get_path('module', 'context_ui') .'/theme',
  18. 'template' => 'context-ui-form',
  19. 'file' => 'theme.inc',
  20. );
  21. $items['context_ui_plugins'] = array(
  22. 'render element' => 'form',
  23. 'path' => drupal_get_path('module', 'context_ui') .'/theme',
  24. 'template' => 'context-ui-plugins',
  25. 'file' => 'theme.inc',
  26. );
  27. $items['context_ui_editor'] = array(
  28. 'render element' => 'form',
  29. 'path' => drupal_get_path('module', 'context_ui') .'/theme',
  30. 'template' => 'context-ui-editor',
  31. 'file' => 'theme.inc',
  32. );
  33. return $items;
  34. }
  35. /**
  36. * Implementation of hook_block_info().
  37. */
  38. function context_ui_block_info() {
  39. $blocks = array();
  40. $blocks['editor'] = array('info' => t('Context editor'), 'admin' => TRUE);
  41. if (module_exists('devel')) {
  42. $blocks['devel'] = array('info' => t('Context inspector'), 'admin' => TRUE);
  43. }
  44. return $blocks;
  45. }
  46. /**
  47. * Implementation of hook_block_view().
  48. */
  49. function context_ui_block_view($delta = '') {
  50. switch ($delta) {
  51. case 'editor':
  52. if (user_access('administer contexts') && strpos($_GET['q'], 'admin/structure/context') === FALSE && $contexts = context_active_contexts()) {
  53. return array(
  54. 'subject' => t('Context editor'),
  55. 'content' => drupal_get_form('context_ui_editor', $contexts),
  56. );
  57. }
  58. break;
  59. case 'devel':
  60. if (module_exists('devel') && $all = context_get()) {
  61. return array(
  62. 'subject' => t('Context inspector'),
  63. 'content' => kdevel_print_object($all),
  64. );
  65. }
  66. break;
  67. }
  68. }
  69. /**
  70. * Implementation of hook_permission().
  71. */
  72. function context_ui_permission() {
  73. $permissions = array();
  74. $permissions['administer contexts'] = array(
  75. 'title' => 'Administer contexts',
  76. 'description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.'
  77. );
  78. $permissions['context ajax block access'] = array(
  79. 'title' => t('Access all blocks'),
  80. 'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
  81. );
  82. return $permissions;
  83. }
  84. /**
  85. * Implementation of hook_menu().
  86. */
  87. function context_ui_menu() {
  88. $items = array();
  89. $items['admin/structure/context/settings'] = array(
  90. 'title' => 'Settings',
  91. 'access callback' => 'user_access',
  92. 'access arguments' => array('administer contexts'),
  93. 'page callback' => 'drupal_get_form',
  94. 'page arguments' => array('context_ui_settings'),
  95. 'type' => MENU_LOCAL_TASK,
  96. 'weight' => 3,
  97. );
  98. $items['context-ui/activate'] = array(
  99. 'title' => 'Activate Context UI',
  100. 'access arguments' => array('administer contexts'),
  101. 'page callback' => 'context_ui_activate',
  102. 'type' => MENU_CALLBACK
  103. );
  104. $items['context-ui/deactivate'] = array(
  105. 'title' => 'Deactivate Context UI',
  106. 'access arguments' => array('administer contexts'),
  107. 'page callback' => 'context_ui_deactivate',
  108. 'type' => MENU_CALLBACK
  109. );
  110. return $items;
  111. }
  112. /**
  113. * Implementation of hook_help().
  114. */
  115. function context_ui_help($path, $arg) {
  116. switch ($path) {
  117. case 'admin/help#context_ui':
  118. $output = file_get_contents(drupal_get_path('module', 'context_ui') .'/README.txt');
  119. return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
  120. case 'admin/structure/context':
  121. return '<p>'. t('Context allows you to manage contextual conditions and reactions for different portions of your site. You can think of each context as representing a "section" of your site. For each context, you can choose the conditions that trigger this context to be active and choose different aspects of Drupal that should react to this active context.') .'</p>';
  122. }
  123. }
  124. /**
  125. * Inline context editor form.
  126. */
  127. function context_ui_editor($form, &$form_state, $contexts) {
  128. $form = array(
  129. '#attributes' => array('class' => array('context-editor')),
  130. '#theme' => array('context_ui_editor'),
  131. 'editables' => array(),
  132. 'contexts' => array('#tree' => TRUE),
  133. 'buttons' => array('#tree' => FALSE),
  134. );
  135. $form['title'] = array(
  136. '#prefix' => '<h2 class="context-editor-title">',
  137. '#markup' => t('Select the context/layer to edit'),
  138. '#suffix' => '</h2>',
  139. '#weight' => -2,
  140. );
  141. //add some help text to the top of the form
  142. $form['help'] = array (
  143. '#prefix' => '<p class="context-help help">',
  144. '#markup' => t('Select which context, or layer of blocks, to edit. Each context is configured to appear on different sets of pages so read the description carefully. When you are done editing click Done and save your changes. You may use the Stop Editing Layout link to close the editor.'),
  145. '#suffix' => '</p>',
  146. '#weight' => -1,
  147. );
  148. $items = array();
  149. $form_context = array();
  150. ksort($contexts);
  151. foreach ($contexts as $context) {
  152. $edit = l(t('Edit'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => array('edit'))));
  153. $done = l(t('Done'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => array('done'))));
  154. $readable_name = ucwords(str_replace('_', ' ', $context->name));
  155. $description = empty($context->description) ? '' : '<br/><div class="label bottom">' . check_plain($context->description) . '</div>';
  156. $items[] = array(
  157. 'data' => '<div class="label top">' . $readable_name. "</div><div class='links'>{$edit} {$done}</div>" . $description,
  158. 'class' => array('context-editable clearfix'),
  159. 'id' => "context-editable-trigger-{$context->name}",
  160. );
  161. $form_context = array(
  162. '#tree' => TRUE,
  163. '#type' => module_exists('admin') ? 'admin_panes' : NULL,
  164. 'context' => array('#type' => 'value', '#value' => $context),
  165. );
  166. // Edit context reactions.
  167. foreach (array_keys(context_reactions()) as $reaction) {
  168. $plugin = context_get_plugin('reaction', $reaction);
  169. if (method_exists($plugin, 'editor_form') && ($plugin_form = $plugin->editor_form($context))) {
  170. $form_context["reaction-{$reaction}"] = $plugin_form + array('#title' => $plugin->title);
  171. }
  172. }
  173. // Add to main form.
  174. $form['contexts'][$context->name] = $form_context;
  175. }
  176. // Display editable contexts in list.
  177. $form['editables']['#markup'] = theme('item_list', array('items' => $items));
  178. // Buttons.
  179. $form['buttons']['save'] = array(
  180. '#type' => 'submit',
  181. '#value' => t('Save changes'),
  182. '#submit' => array('context_ui_editor_submit'),
  183. );
  184. $form['buttons']['cancel'] = array(
  185. '#type' => 'submit',
  186. '#value' => t('Reset'),
  187. '#submit' => array('context_ui_editor_cancel'),
  188. );
  189. $form['stop'] = array(
  190. '#markup' => l(t('Stop Editing Layout'), 'context-ui/deactivate', array(
  191. 'query' => array('destination' => current_path()),
  192. 'attributes' => array('class' => array('context_ui_dialog-stop')),
  193. )
  194. ),
  195. );
  196. return $form;
  197. }
  198. /**
  199. * Values processor for context_ui_editor_submit().
  200. * Split out for reuse by overriding submit handlers.
  201. */
  202. function context_ui_editor_process($values) {
  203. $context = $values['context'];
  204. foreach (array_keys(context_conditions()) as $condition) {
  205. if (isset($values['condition'][$condition])) {
  206. $plugin = context_get_plugin('condition', $condition);
  207. if ($plugin && method_exists($plugin, 'editor_form_submit')) {
  208. $context->conditions[$condition]['values'] = $plugin->editor_form_submit($context, $values['condition'][$condition]);
  209. }
  210. }
  211. if (isset($context->conditions[$condition]) && context_empty($context->conditions[$condition]['values'])) {
  212. unset($context->conditions[$condition]);
  213. }
  214. }
  215. foreach (array_keys(context_reactions()) as $reaction) {
  216. if (isset($values["reaction-{$reaction}"])) {
  217. $plugin = context_get_plugin('reaction', $reaction);
  218. if ($plugin && method_exists($plugin, 'editor_form_submit')) {
  219. $context->reactions[$reaction] = $plugin->editor_form_submit($context, $values["reaction-{$reaction}"]);
  220. }
  221. }
  222. if (isset($context->reactions[$reaction]) && context_empty($context->reactions[$reaction])) {
  223. unset($context->reactions[$reaction]);
  224. }
  225. }
  226. return $context;
  227. }
  228. /**
  229. * Save handler for context_block_editor().
  230. */
  231. function context_ui_editor_submit(&$form, &$form_state) {
  232. foreach ($form_state['values']['contexts'] as $name => $values) {
  233. $original_reactions = var_export($values['context']->reactions, TRUE);
  234. $context = context_ui_editor_process($values);
  235. //compare string values instead of actual objects to avoid problems with aliasing
  236. if (($original_reactions !== var_export($context->reactions, TRUE))) {
  237. if (context_save($context)) {
  238. drupal_set_message(t('Saved %title.', array(
  239. '%title' => (!empty($context->description) ? $context->description : $context->name)
  240. )));
  241. }
  242. else {
  243. drupal_set_message(t('Could not save context %title.', array('%title' => $context->name)), 'error');
  244. }
  245. }
  246. }
  247. return;
  248. }
  249. /**
  250. * Cancel handler for context_block_editor().
  251. */
  252. function context_ui_editor_cancel(&$form, &$form_state) {
  253. return;
  254. }
  255. /**
  256. * Settings form.
  257. */
  258. function context_ui_settings($form, &$form_state) {
  259. $form = array();
  260. foreach (context_conditions() as $condition => $info) {
  261. if ($plugin = context_get_plugin('condition', $condition)) {
  262. $settings_form = $plugin->settings_form();
  263. if ($settings_form) {
  264. $form['conditions'][$condition] = $settings_form;
  265. $form['conditions'][$condition]['#tree'] = FALSE;
  266. $form['conditions'][$condition]['#type'] = 'fieldset';
  267. $form['conditions'][$condition]['#title'] = $info['title'];
  268. }
  269. }
  270. }
  271. foreach (context_reactions() as $reaction => $info) {
  272. if ($plugin = context_get_plugin('reaction', $reaction)) {
  273. $settings_form = $plugin->settings_form();
  274. if ($settings_form) {
  275. $form['reactions'][$reaction] = $settings_form;
  276. $form['reactions'][$reaction]['#tree'] = FALSE;
  277. $form['reactions'][$reaction]['#type'] = 'fieldset';
  278. $form['reactions'][$reaction]['#title'] = $info['title'];
  279. }
  280. }
  281. }
  282. $form['context_ui_dialog_enabled'] = array(
  283. '#type' => 'checkbox',
  284. '#title' => t('Use context editor dialog'),
  285. '#default_value' => context_ui_dialog_is_enabled(),
  286. '#description' => t('When enabled all contextual links will have a <em>Edit layout</em> link that will refresh the page with the context editor in a dialog box.'),
  287. );
  288. $form = system_settings_form($form);
  289. $form['#submit'][] = 'context_ui_settings_submit';
  290. return $form;
  291. }
  292. /**
  293. * Extra submit handler for context_ui_settings.
  294. * Mark the menu cache as needing a rebuild.
  295. */
  296. function context_ui_settings_submit($form, &$form_state) {
  297. variable_set('menu_rebuild_needed', TRUE);
  298. }
  299. /**
  300. * context_ui_dialog_is_enabled test if the dialog is enabled
  301. */
  302. function context_ui_dialog_is_enabled() {
  303. return variable_get("context_ui_dialog_enabled", FALSE);
  304. }
  305. /**
  306. * Implementation of hook_page_alter().
  307. *
  308. * If we have the dialog enabled and active build the dialog
  309. * and add to the page
  310. */
  311. function context_ui_page_alter(&$page) {
  312. $contexts = context_active_contexts();
  313. if (
  314. context_ui_dialog_is_enabled() &&
  315. context_isset('context_ui', 'context_ui_editor_present')
  316. ) {
  317. $contexts = context_active_contexts();
  318. $form = drupal_get_form('context_ui_editor', $contexts);
  319. $path = drupal_get_path('module', 'context_ui');
  320. drupal_add_library('system', 'ui.dialog');
  321. drupal_add_js($path . '/context_ui_dialog.js', array('type' => 'file', 'weight' => 50));
  322. drupal_add_css($path . '/context_ui_dialog.css');
  323. //figure out which region to put it in - allow it to be configured for themes using different regions
  324. $placement = variable_get('context_ui_editor_block_region', 'content');
  325. $page[$placement]['context_ui_editor'] = array(
  326. 0 => array(
  327. '#type' => 'markup',
  328. '#markup' => '<div style="display:none;" id="context_ui_dialog-context-ui">' . drupal_render($form) . '<!--[if IE 8 ]><div id="context_ui_dialog-shadow"></div><![endif]--></div>',
  329. ),
  330. );
  331. }
  332. }
  333. /**
  334. * Implementation of hook_menu_contextual_links_alter().
  335. *
  336. * we we have the dialog enabled lets add a link to all contextual links
  337. * to activate it.
  338. */
  339. function context_ui_menu_contextual_links_alter(&$links, $router_item, $root_path) {
  340. if(context_ui_dialog_is_enabled() &&
  341. !context_isset('context_ui', 'context_ui_editor_present') && user_access('administer contexts')) {
  342. $links['layout'] = array(
  343. 'href' => 'context-ui/activate',
  344. 'title' => t('Configure layout'),
  345. 'localized_options' => array(
  346. 'query' => array('destination'=> $_GET['q']),
  347. 'options' => array('html' => FALSE, 'attributes' => array()),
  348. ),
  349. );
  350. }
  351. }
  352. /**
  353. * A page call back to activate the context_ui inline editor dialog.
  354. */
  355. function context_ui_activate() {
  356. if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
  357. $_SESSION['context_ui_active'] = $_GET['destination'];
  358. drupal_goto($_GET['destination']);
  359. }
  360. }
  361. /**
  362. * A page call back to deactivate the context_ui inline editor dialog.
  363. * This is semi unecessary as context editor will auto deactivate upon going to any
  364. * page other than the destination from the start. However, its useful as a place
  365. * to navigate to when deactivating context_ui_editor
  366. */
  367. function context_ui_deactivate() {
  368. if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
  369. $_SESSION['context_ui_active'] = FALSE;
  370. drupal_goto($_GET['destination']);
  371. }
  372. }
  373. /**
  374. * Implemenation of hook_init().
  375. *
  376. * If the session says we should have an active dialog set a context variable to tell everything else
  377. * Ignores ajax requests.
  378. */
  379. function context_ui_init() {
  380. if (!empty($_SESSION['context_ui_active'])) {
  381. $path = $_SESSION['context_ui_active'];
  382. if( $path == request_path() || $path == drupal_get_path_alias() || $path == drupal_get_normal_path(request_path()) ) {
  383. context_set('context_ui', 'context_ui_editor_present', TRUE);
  384. }
  385. }
  386. // Turn off functionality has been moved to hook_page_build() to prevent non-pages from triggering it
  387. }
  388. /**
  389. * Implementation of hook_page_build().
  390. * Turn off the context_ui functionality if we move to a different page
  391. */
  392. function context_ui_page_build(&$page) {
  393. if (!context_get('context_ui', 'context_ui_editor_present') && isset($_SESSION['context_ui_active'])) {
  394. $_SESSION['context_ui_active'] = FALSE;
  395. }
  396. }
  397. /**
  398. * Ajax callback to get the list of available blocks
  399. *
  400. */
  401. function context_ui_get_available_blocks() {
  402. drupal_json_output(array('lols' => 'testing'));
  403. }