context_export_ui.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. /**
  3. * CTools export UI extending class. Slightly customized for Context.
  4. */
  5. class context_export_ui extends ctools_export_ui {
  6. function list_form(&$form, &$form_state) {
  7. parent::list_form($form, $form_state);
  8. $form['top row']['submit'] = $form['bottom row']['submit'];
  9. $form['top row']['reset'] = $form['bottom row']['reset'];
  10. $form['bottom row']['#access'] = FALSE;
  11. // Invalidate the context cache.
  12. context_invalidate_cache();
  13. return;
  14. }
  15. function list_css() {
  16. ctools_add_css('export-ui-list');
  17. drupal_add_css(drupal_get_path("module", "context_ui") ."/context_ui.css");
  18. }
  19. function list_render(&$form_state) {
  20. $table = array(
  21. 'header' => $this->list_table_header(),
  22. 'rows' => $this->rows,
  23. 'attributes' => array(
  24. 'class' => array('context-admin'),
  25. 'id' => 'ctools-export-ui-list-items',
  26. ),
  27. );
  28. return theme('table', $table);
  29. }
  30. function list_build_row($item, &$form_state, $operations) {
  31. $name = $item->name;
  32. // Add a row for tags.
  33. $tag = !empty($item->tag) ? $item->tag : t('< Untagged >');
  34. if (!isset($this->rows[$tag])) {
  35. $this->rows[$tag]['data'] = array();
  36. $this->rows[$tag]['data'][] = array('data' => check_plain($tag), 'colspan' => 3, 'class' => array('tag'));
  37. $this->sorts["{$tag}"] = $tag;
  38. }
  39. // Build row for each context item.
  40. $this->rows["{$tag}:{$name}"]['data'] = array();
  41. $this->rows["{$tag}:{$name}"]['class'] = !empty($item->disabled) ? array('ctools-export-ui-disabled') : array('ctools-export-ui-enabled');
  42. $this->rows["{$tag}:{$name}"]['data'][] = array(
  43. 'data' => check_plain($name) . "<div class='description'>" . check_plain($item->description) . "</div>",
  44. 'class' => array('ctools-export-ui-name')
  45. );
  46. $this->rows["{$tag}:{$name}"]['data'][] = array(
  47. 'data' => check_plain($item->type),
  48. 'class' => array('ctools-export-ui-storage')
  49. );
  50. $this->rows["{$tag}:{$name}"]['data'][] = array(
  51. 'data' => theme('links', array(
  52. 'links' => $operations,
  53. 'attributes' => array('class' => array('links inline'))
  54. )),
  55. 'class' => array('ctools-export-ui-operations'),
  56. );
  57. // Sort by tag, name.
  58. $this->sorts["{$tag}:{$name}"] = $tag . $name;
  59. }
  60. /**
  61. * Override of edit_form_submit().
  62. * Don't copy values from $form_state['values'].
  63. */
  64. function edit_form_submit(&$form, &$form_state) {
  65. if (!empty($this->plugin['form']['submit'])) {
  66. $this->plugin['form']['submit']($form, $form_state);
  67. }
  68. context_invalidate_cache();
  69. }
  70. /**
  71. * Override default final validation for ctools. With import wizard
  72. * it was possible to get default ctools export ui name validation
  73. * rules, this ensures we always get ours.
  74. */
  75. function edit_finish_validate(&$form, &$form_state) {
  76. if ($form_state['op'] != 'edit') {
  77. // Validate the name. Fake an element for form_error().
  78. $export_key = $this->plugin['export']['key'];
  79. $element = array(
  80. '#value' => $form_state['item']->{$export_key},
  81. '#parents' => array('name'),
  82. );
  83. $form_state['plugin'] = $this->plugin;
  84. context_ui_edit_name_validate($element, $form_state);
  85. }
  86. }
  87. }
  88. /**
  89. * Generates the omnibus context definition editing form.
  90. *
  91. * @param $form
  92. * Form array to populate.
  93. * @param $form_state
  94. * Form state array
  95. */
  96. function context_ui_form(&$form, &$form_state) {
  97. $conditions = array_keys(context_conditions());
  98. sort($conditions);
  99. $reactions = array_keys(context_reactions());
  100. sort($reactions);
  101. $context = $form_state['item'];
  102. if (!empty($form_state['input'])) {
  103. $context = _context_ui_rebuild_from_input($context, $form_state['input'], $conditions, $reactions);
  104. }
  105. $form['#base'] = 'context_ui_form';
  106. $form['#theme'] = 'context_ui_form';
  107. // Core context definition
  108. $form['info']['#type'] = 'fieldset';
  109. $form['info']['#tree'] = FALSE;
  110. $form['info']['name']['#element_validate'] = array('context_ui_edit_name_validate');
  111. $form['info']['tag'] = array(
  112. '#title' => t('Tag'),
  113. '#type' => 'textfield',
  114. '#required' => FALSE,
  115. '#maxlength' => 255,
  116. '#default_value' => isset($context->tag) ? $context->tag : '',
  117. '#description' => t('Example: <code>theme</code>') . '<br/>' . t('A tag to group this context with others.'),
  118. );
  119. $form['info']['description'] = array(
  120. '#title' => t('Description'),
  121. '#type' => 'textfield',
  122. '#required' => FALSE,
  123. '#maxlength' => 255,
  124. '#default_value' => isset($context->description) ? $context->description: '',
  125. '#description' => t('The description of this context definition.'),
  126. );
  127. // Condition mode
  128. $form['condition_mode'] = array(
  129. '#type' => 'checkbox',
  130. '#default_value' => isset($context->condition_mode) ? $context->condition_mode : FALSE,
  131. '#title' => t('Require all conditions'),
  132. '#description' => t('If checked, all conditions must be met for this context to be active. Otherwise, the first condition that is met will activate this context.')
  133. );
  134. // Condition plugin forms
  135. $form['conditions'] = array(
  136. '#theme' => 'context_ui_plugins',
  137. '#title' => t('Conditions'),
  138. '#description' => t('Trigger the activation of this context.'),
  139. '#tree' => TRUE,
  140. 'selector' => array(
  141. '#type' => 'select',
  142. '#options' => array(0 => '<' . t('Add a condition') . '>'),
  143. '#default_value' => 0,
  144. ),
  145. 'state' => array(
  146. '#attributes' => array('class' => array('context-plugins-state')),
  147. '#type' => 'hidden',
  148. ),
  149. 'plugins' => array('#tree' => TRUE),
  150. );
  151. foreach ($conditions as $condition) {
  152. if ($plugin = context_get_plugin('condition', $condition)) {
  153. $form['conditions']['plugins'][$condition] = array(
  154. '#tree' => TRUE,
  155. '#plugin' => $plugin,
  156. '#context_enabled' => isset($context->conditions[$condition]), // This flag is used at the theme layer.
  157. 'values' => $plugin->condition_form($context),
  158. 'options' => $plugin->options_form($context),
  159. );
  160. $form['conditions']['selector']['#options'][$condition] = $plugin->title;
  161. }
  162. }
  163. // Reaction plugin forms
  164. $form['reactions'] = array(
  165. '#theme' => 'context_ui_plugins',
  166. '#title' => t('Reactions'),
  167. '#description' => t('Actions to take when this context is active.'),
  168. '#tree' => TRUE,
  169. 'selector' => array(
  170. '#type' => 'select',
  171. '#options' => array(0 => '<' . t('Add a reaction') . '>'),
  172. '#default_value' => 0,
  173. ),
  174. 'state' => array(
  175. '#attributes' => array('class' => array('context-plugins-state')),
  176. '#type' => 'hidden',
  177. ),
  178. 'plugins' => array('#tree' => TRUE),
  179. );
  180. foreach ($reactions as $reaction) {
  181. if ($plugin = context_get_plugin('reaction', $reaction)) {
  182. $form['reactions']['plugins'][$reaction] = $plugin->options_form($context) + array(
  183. '#plugin' => $plugin,
  184. '#context_enabled' => isset($context->reactions[$reaction]), // This flag is used at the theme layer.
  185. );
  186. $form['reactions']['selector']['#options'][$reaction] = $plugin->title;
  187. }
  188. }
  189. }
  190. /**
  191. * Handle the complex job of rebuilding a Context from submission data in the case of a validation error.
  192. *
  193. * @param $context
  194. * The context object to modify.
  195. * @param $input
  196. * A form submission values
  197. * @param $conditions
  198. * The full list of condition plugins
  199. * @param $reactions
  200. * The full list of reaction plugins
  201. *
  202. * @return
  203. * A context object
  204. */
  205. function _context_ui_rebuild_from_input($context, $input, $conditions, $reactions) {
  206. $condition_defaults = array();
  207. foreach ($conditions as $condition) {
  208. if ($plugin = context_get_plugin('condition', $condition)) {
  209. $condition_defaults[$condition] = array(
  210. 'values' => $plugin->condition_form($context),
  211. 'options' => $plugin->options_form($context),
  212. );
  213. }
  214. }
  215. $input['conditions']['plugins'] = array_merge($condition_defaults, $input['conditions']['plugins']);
  216. $reaction_defaults = array();
  217. foreach ($reactions as $reaction) {
  218. if ($plugin = context_get_plugin('reaction', $reaction)) {
  219. $reaction_defaults[$reaction] = $plugin->options_form($context);
  220. }
  221. }
  222. $input['reactions']['plugins'] = array_merge($reaction_defaults, $input['reactions']['plugins']);
  223. return context_ui_form_process($context, $input, FALSE);
  224. }
  225. /**
  226. * Modifies a context object from submitted form values.
  227. *
  228. * @param $context
  229. * The context object to modify.
  230. * @param $form
  231. * A form array with submitted values
  232. * @param $submit
  233. * A flag indicating if we are building a context on submit. If on
  234. * submit, it will clear out conditions/reactions that are empty.
  235. *
  236. * @return
  237. * A context object
  238. */
  239. function context_ui_form_process($context, $form, $submit = TRUE) {
  240. $context->name = isset($form['name']) ? $form['name'] : $context->name;
  241. $context->description = isset($form['description']) ? $form['description'] : NULL;
  242. $context->tag = isset($form['tag']) ? $form['tag'] : NULL;
  243. $context->condition_mode = isset($form['condition_mode']) ? $form['condition_mode'] : NULL;
  244. $context->conditions = array();
  245. $context->reactions = array();
  246. if (!empty($form['conditions'])) {
  247. $enabled = explode(',', $form['conditions']['state']);
  248. foreach ($form['conditions']['plugins'] as $condition => $values) {
  249. if (in_array($condition, $enabled, TRUE) && ($plugin = context_get_plugin('condition', $condition))) {
  250. if (isset($values['values'])) {
  251. $context->conditions[$condition]['values'] = $plugin->condition_form_submit($values['values']);
  252. }
  253. if (isset($values['options'])) {
  254. $context->conditions[$condition]['options'] = $plugin->options_form_submit($values['options']);
  255. }
  256. if ($submit && context_empty($context->conditions[$condition]['values'])) {
  257. unset($context->conditions[$condition]);
  258. }
  259. }
  260. }
  261. }
  262. if (!empty($form['reactions'])) {
  263. $enabled = explode(',', $form['reactions']['state']);
  264. foreach ($form['reactions']['plugins'] as $reaction => $values) {
  265. if (in_array($reaction, $enabled, TRUE) && ($plugin = context_get_plugin('reaction', $reaction))) {
  266. if (isset($values)) {
  267. $context->reactions[$reaction] = $plugin->options_form_submit($values);
  268. }
  269. if ($submit && context_empty($context->reactions[$reaction])) {
  270. unset($context->reactions[$reaction]);
  271. }
  272. }
  273. }
  274. }
  275. return $context;
  276. }
  277. /**
  278. * Submit handler for main context_ui form.
  279. */
  280. function context_ui_form_submit($form, &$form_state) {
  281. $form_state['item'] = context_ui_form_process($form_state['item'], $form_state['values']);
  282. }
  283. /**
  284. * Replacement for ctools_export_ui_edit_name_validate(). Allow dashes.
  285. */
  286. function context_ui_edit_name_validate($element, &$form_state) {
  287. $plugin = $form_state['plugin'];
  288. // Check for string identifier sanity
  289. if (!preg_match('!^[a-z0-9_-]+$!', $element['#value'])) {
  290. form_error($element, t('The name can only consist of lowercase letters, underscores, dashes, and numbers.'));
  291. return;
  292. }
  293. // Check for name collision
  294. if ($form_state['op'] != 'edit') {
  295. if (empty($form_state['item']->export_ui_allow_overwrite) && $exists = ctools_export_crud_load($plugin['schema'], $element['#value'])) {
  296. form_error($element, t('A @plugin with this name already exists. Please choose another name or delete the existing item before creating a new one.', array('@plugin' => $plugin['title singular'])));
  297. }
  298. }
  299. }