1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * UI-related improvements to the Workflow module and tokens for Rules. |
---|
6 | * |
---|
7 | * 1a) Replaces the traditional workflow radio-buttons by either a drop-down or |
---|
8 | * single-action buttons featuring context-sensitive labels (using replacement |
---|
9 | * tokens) for a more intuitive user experience. |
---|
10 | * See also the discussion on intelligent buttons at drupal.org/node/282122. |
---|
11 | * All three UI styles (radio, dropw-down or single-action) are available as a |
---|
12 | * block. |
---|
13 | * 1b) Suppresses the workflow schedule transition form if not selected by the |
---|
14 | * user. |
---|
15 | * 2) The module also defines tokens which when used with Rules allow you to |
---|
16 | * more easily invoke actions when something did NOT happen for some time. |
---|
17 | * |
---|
18 | * Re 1a) |
---|
19 | * Let's say we have a basic workflow with states "draft", "review" and "live". |
---|
20 | * Traditionally authors and moderators must select the next state by pressing |
---|
21 | * the correct radio-button and clicking submit. Experience from the field |
---|
22 | * suggests that not everybody finds this intuitive. Rather than having to |
---|
23 | * think in terms of state transitions, users prefer to press a button with a |
---|
24 | * an explanatory label that clearly expresses what is going to happen. |
---|
25 | * Using this module authors will find on the edit form a couple of clearly |
---|
26 | * labeled buttons: "Save as draft, don't submit" and "Submit for publication". |
---|
27 | * In old workflow-speak the latter action is represented by radio buttons plus |
---|
28 | * a submit button and read less intuitively as: transition workflow state |
---|
29 | * from "draft" to "review". |
---|
30 | * Similarly, with this module a moderator will see on their edit form buttons |
---|
31 | * like "Reject and return to author John" (i.e. "review -> draft") and |
---|
32 | * "Publish this" ("review -> live"). |
---|
33 | * The alternative buttons appear on: |
---|
34 | * a) the node edit form (node/%/edit) |
---|
35 | * b) the comment edit form, if enabled |
---|
36 | * c) the workflow tab, if enabled (node/%/workflow) |
---|
37 | * |
---|
38 | * Re 2) |
---|
39 | * This module defines a replacement token [node:workflow-state-age], which |
---|
40 | * when used in a scheduled rule set, make it easier to invoke actions when |
---|
41 | * a workflow state was NOT changed after a specified elapsed time. |
---|
42 | * See drupal.org/project/workflow_extensions for full instructions on |
---|
43 | * how to do this using Rules. |
---|
44 | */ |
---|
45 | |
---|
46 | define('WORKFLOW_EXTENSIONS_UI_RADIOS', 1); // the original Workflow style |
---|
47 | define('WORKFLOW_EXTENSIONS_UI_BUTTONS', 2); // single-action buttons |
---|
48 | define('WORKFLOW_EXTENSIONS_UI_DROPDOWN', 3); // dropdown selector + update |
---|
49 | |
---|
50 | /** |
---|
51 | * Implementation of hook_perm(). |
---|
52 | */ |
---|
53 | function workflow_extensions_perm() { |
---|
54 | return array( |
---|
55 | 'change workflow state via node edit form', |
---|
56 | 'edit workflow log', |
---|
57 | 'view workflow state change block even when state cannot be changed'); |
---|
58 | } |
---|
59 | |
---|
60 | /** |
---|
61 | * Implementation of hook_menu(). |
---|
62 | */ |
---|
63 | function workflow_extensions_menu() { |
---|
64 | $items = array(); |
---|
65 | $items['workflow-log/%workflow_state_transition_record'] = array( // maps to function workflow_state_transition_record_load() |
---|
66 | 'title' => 'Edit workflow log comment', |
---|
67 | 'description' => 'Edit workflow state transition comment.', |
---|
68 | 'page callback' => 'drupal_get_form', |
---|
69 | 'page arguments' => array('workflow_extensions_workflow_comment_edit_form', 1), |
---|
70 | 'access arguments' => array('edit workflow log') |
---|
71 | ); |
---|
72 | $items['admin/settings/workflow_extensions'] = array( |
---|
73 | 'title' => 'Workflow extensions', |
---|
74 | 'description' => 'Configure workflow form style (buttons and labels).', |
---|
75 | 'page callback' => 'drupal_get_form', |
---|
76 | 'page arguments' => array('workflow_extensions_admin_configure'), |
---|
77 | 'access arguments' => array('administer site configuration'), |
---|
78 | 'file' => 'workflow_extensions.admin.inc' |
---|
79 | ); |
---|
80 | return $items; |
---|
81 | } |
---|
82 | |
---|
83 | /** |
---|
84 | * Load function belonging to the above menu option 'workflow-log/%workflow-state-transition-record'. |
---|
85 | * Maps to this function just like 'node/%node' maps to node_load(). |
---|
86 | * |
---|
87 | * @param $hid |
---|
88 | * The ID of the workflow state transition record to load. |
---|
89 | * @return |
---|
90 | * object representing one row from the {workflow_node_history} table |
---|
91 | */ |
---|
92 | function workflow_state_transition_record_load($hid) { |
---|
93 | $workflow_state_transition_record = db_fetch_object(db_query('SELECT * FROM {workflow_node_history} WHERE hid = %d', $hid)); |
---|
94 | return $workflow_state_transition_record; |
---|
95 | } |
---|
96 | |
---|
97 | /** |
---|
98 | * Display a text area populated with the selected workflow log comment and |
---|
99 | * allow the user to modify and save it. |
---|
100 | */ |
---|
101 | function workflow_extensions_workflow_comment_edit_form($form_state, $workflow_state_transition_record) { |
---|
102 | $form = array(); |
---|
103 | $form['hid'] = array('#type' => 'value', '#value' => $workflow_state_transition_record->hid); |
---|
104 | $form['nid'] = array('#type' => 'value', '#value' => $workflow_state_transition_record->nid); |
---|
105 | $form['workflow']['workflow_comment'] = array( |
---|
106 | '#type' => 'textarea', |
---|
107 | '#title' => t('Comment'), |
---|
108 | '#description' => t('Modify this workflow state transition comment and press submit.'), |
---|
109 | '#default_value' => $workflow_state_transition_record->comment, |
---|
110 | '#rows' => 2, |
---|
111 | ); |
---|
112 | $form['submit'] = array( |
---|
113 | '#type' => 'submit', |
---|
114 | '#value' => t('Submit') |
---|
115 | ); |
---|
116 | return $form; |
---|
117 | } |
---|
118 | |
---|
119 | /** |
---|
120 | * Submit handler for the workflow transition comment edit form. |
---|
121 | * |
---|
122 | * @see workflow_extensions_workflow_comment_edit_form() |
---|
123 | */ |
---|
124 | function workflow_extensions_workflow_comment_edit_form_submit($form, &$form_state) { |
---|
125 | $hid = $form_state['values']['hid']; |
---|
126 | $comment = $form_state['values']['workflow_comment']; |
---|
127 | |
---|
128 | db_query("UPDATE {workflow_node_history} SET comment = '%s' WHERE hid = %d", $comment, $hid); |
---|
129 | |
---|
130 | $nid = $form_state['values']['nid']; |
---|
131 | |
---|
132 | // Whatever is set here, is overriden by the "?destination=..." parameter, if present |
---|
133 | $form_state['redirect'] = module_exists('views') && views_get_view('workflow_history') |
---|
134 | ? "workflow-history/$nid" |
---|
135 | : (workflow_node_tab_access(node_load($nid)) ? "node/$nid/workflow" : "node/$nid"); |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * Implementation of hook_form_alter(). |
---|
140 | * |
---|
141 | * 1) Remove the Workflow radio buttons and replace each state transition by a |
---|
142 | * submit button with a configurable, explanatory label. |
---|
143 | * To allow saving of edits to the node without a state transition, display |
---|
144 | * an additional button "Save, don't submit" (or similar). |
---|
145 | * 2) If on the create/edit form suppress the workflow fieldset if the user |
---|
146 | * does not have the relevant permission |
---|
147 | * 3) If the schedule state transition form is enabled, suppress it until the |
---|
148 | * user clicks the radio button to reveal it. |
---|
149 | * 4) Add an (extra) form validator |
---|
150 | */ |
---|
151 | function workflow_extensions_form_alter(&$form, &$form_state, $form_id) { |
---|
152 | |
---|
153 | // If there's no Workflow fieldset, then we have nothing further to do. |
---|
154 | if (!isset($form['#wf'])) { // was $form['workflow'] but need to exclude content type edit form |
---|
155 | return; |
---|
156 | } |
---|
157 | |
---|
158 | // 4) Add form validator |
---|
159 | if (empty($form['#validate'])) { |
---|
160 | $form['#validate'] = array(); |
---|
161 | } |
---|
162 | elseif (!is_array($form['#validate'])) { |
---|
163 | $form['#validate'] = array($form['#validate']); |
---|
164 | } |
---|
165 | $form['#validate'][] = 'workflow_extensions_workflow_form_validate'; |
---|
166 | |
---|
167 | // 2) Suppress Workflow fieldset on the create/edit form if not permitted. |
---|
168 | if (isset($form['#id']) && $form['#id'] == 'node-form' && !user_access('change workflow state via node edit form')) { |
---|
169 | unset($form['workflow']); |
---|
170 | return; |
---|
171 | } |
---|
172 | |
---|
173 | // The next if-statement implements point 3) above |
---|
174 | if (variable_get('workflow_extensions_display_schedule_toggle', TRUE)) { |
---|
175 | $path = drupal_get_path('module', 'workflow_extensions'); |
---|
176 | drupal_add_js($path . '/workflow_schedule.js', 'module'); |
---|
177 | } |
---|
178 | |
---|
179 | // The rest of this function implements point 1) |
---|
180 | $workflow_name = workflow_extensions_extract_workflow_name($form); |
---|
181 | $workflow_radios = $form['workflow'][$workflow_name]; |
---|
182 | |
---|
183 | if (is_array($workflow_radios) && isset($workflow_radios['#options'])) { |
---|
184 | // Use the form to work out the potential state transitions for this user. |
---|
185 | $states = $workflow_radios['#options']; |
---|
186 | // $states will be empty when creating node |
---|
187 | if (!empty($states)) { |
---|
188 | |
---|
189 | $title = variable_get('workflow_extensions_change_state_form_title', ''); |
---|
190 | if (!empty($title)) { |
---|
191 | if (trim($title) == '<none>') { |
---|
192 | unset($form['workflow'][$workflow_name]['#title']); |
---|
193 | } |
---|
194 | else { |
---|
195 | $form['workflow'][$workflow_name]['#title'] = workflow_extensions_replace_tokens_raw($title); |
---|
196 | } |
---|
197 | } |
---|
198 | |
---|
199 | if (empty($form['#submit'])) { |
---|
200 | // This seems to happen as a side-effect of using hook_forms(), i.e |
---|
201 | // the case where workflow_extensions_change_state_form() is called, |
---|
202 | // for instance when the state change form appears in a block or View. |
---|
203 | // In the latter case, we also create ourselves an option to redirect |
---|
204 | // to page different from the default (which is node/%), as set in |
---|
205 | // workflow_tab_form_submit(). |
---|
206 | $form['#submit'] = array('workflow_tab_form_submit', 'workflow_extensions_form_redirect'); |
---|
207 | } |
---|
208 | |
---|
209 | switch (variable_get('workflow_extensions_ui_style', WORKFLOW_EXTENSIONS_UI_BUTTONS)) { |
---|
210 | |
---|
211 | case WORKFLOW_EXTENSIONS_UI_BUTTONS: |
---|
212 | if (count($states) > 1) { |
---|
213 | _workflow_extensions_replace_with_buttons($form, $workflow_name); |
---|
214 | } |
---|
215 | break; |
---|
216 | |
---|
217 | case WORKFLOW_EXTENSIONS_UI_DROPDOWN: |
---|
218 | _workflow_extensions_replace_with_dropdown($form, $workflow_name); |
---|
219 | // no break; |
---|
220 | |
---|
221 | default: // radios |
---|
222 | if (isset($form['submit'])) { |
---|
223 | $submit_label = variable_get('workflow_extensions_change_state_button_label', ''); |
---|
224 | if (!empty($submit_label)) { |
---|
225 | $form['submit']['#value'] = workflow_extensions_replace_tokens_raw($submit_label); |
---|
226 | } |
---|
227 | } |
---|
228 | break; |
---|
229 | } |
---|
230 | } |
---|
231 | } |
---|
232 | } |
---|
233 | |
---|
234 | /** |
---|
235 | * Implementation of hook_forms(); |
---|
236 | * |
---|
237 | * Called as a result of the fact that there are no form handlers for the |
---|
238 | * unique form_id's generated in workflow_extensions_change_state_form(). |
---|
239 | * Here we map these form_id's back to the same 'workflow_tab_form'. This |
---|
240 | * allows us to have multiple copies of the same form on the same page. |
---|
241 | * Note: first of the args is typically the node object. |
---|
242 | */ |
---|
243 | function workflow_extensions_forms($form_id, $args) { |
---|
244 | if (strpos($form_id, 'workflow_tab_form_nid') === 0) { |
---|
245 | $form = array( |
---|
246 | $form_id => array( |
---|
247 | 'callback' => 'workflow_tab_form', |
---|
248 | 'callback arguments' => array() |
---|
249 | ) |
---|
250 | ); |
---|
251 | return $form; |
---|
252 | } |
---|
253 | } |
---|
254 | |
---|
255 | /** |
---|
256 | * Validate the workflow form, in particular the state transition comment and |
---|
257 | * the scheduled state transition time (the date is a drop-down so requires no |
---|
258 | * validation). |
---|
259 | */ |
---|
260 | function workflow_extensions_workflow_form_validate($form, &$form_state) { |
---|
261 | $nid = substr($form['#id'], strrpos($form['#id'], '-') + 1); |
---|
262 | $title = isset($form_state['values']['title']) ? $form_state['values']['title'] : $form_state['values']['node']->title; |
---|
263 | |
---|
264 | if (!empty($form_state['values']['workflow_scheduled_hour'])) { |
---|
265 | if (!strtotime($form_state['values']['workflow_scheduled_hour'])) { |
---|
266 | form_set_error(is_numeric($nid) ? "workflow_scheduled_hour_$nid" : 'workflow_scheduled_hour', t('%title: scheduled time is not in the correct format.', array('%title' => $title))); |
---|
267 | } |
---|
268 | } |
---|
269 | if (!variable_get('workflow_extensions_allow_blank_comments', TRUE)) { |
---|
270 | if (!isset($form_state['values']['nid']) && !isset($form_state['values']['node'])) { |
---|
271 | // Bypass node creation |
---|
272 | return; |
---|
273 | } |
---|
274 | $comment = $form_state['values']['workflow_comment']; |
---|
275 | if (!trim($comment)) { |
---|
276 | form_set_error(is_numeric($nid) ? "workflow_comment_$nid" : 'workflow_comment', t('%title: please enter a non-blank comment for the workflow log.', array('%title' => $title))); |
---|
277 | } |
---|
278 | } |
---|
279 | } |
---|
280 | |
---|
281 | /** |
---|
282 | * Handler for the single-action submit buttons on the edit form. |
---|
283 | * Does NOT get called when radio buttons or drop-down are used. |
---|
284 | */ |
---|
285 | function workflow_extensions_form_submit($form, &$form_state) { |
---|
286 | // In the original form_submit handler that we pass control to next, the |
---|
287 | // selected workflow state is taken from form_state['values']['workflow']. So |
---|
288 | // that's the entry we need to set here in accordance with the clicked button. |
---|
289 | // See node_form_submit() -> node_submit() for the edit form. |
---|
290 | // See workflow_tab_form_submit() for the Workflow tab. |
---|
291 | $form_state['values']['workflow'] = $form_state['clicked_button']['#to_state']; |
---|
292 | // ... now proceed to next handler, e.g. node_form_submit for a normal save |
---|
293 | } |
---|
294 | |
---|
295 | /** |
---|
296 | * If the workflow state was not transitioned via either the node edit form or |
---|
297 | * the Workflow tab, then redirect to a configurable page, e.g. some View. |
---|
298 | */ |
---|
299 | function workflow_extensions_form_redirect($form, &$form_state) { |
---|
300 | if (arg(0) != 'node') { |
---|
301 | $path = variable_get('workflow_extensions_redirect_page', ''); // @todo: make this a UI config option |
---|
302 | $form_state['redirect'] = empty($path) ? $_GET['q'] : $path; // @todo: save query-string too (Views pager) |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | function _workflow_extensions_replace_with_buttons(&$form, $workflow_name) { |
---|
307 | $current_sid = $form['workflow'][$workflow_name]['#default_value']; |
---|
308 | if (function_exists('workflow_get_state_name')) { |
---|
309 | $current_state_name = workflow_get_state_name($current_sid); |
---|
310 | } |
---|
311 | else { |
---|
312 | $current_state = workflow_get_state($current_sid); |
---|
313 | $current_state_name = $current_state['state']; |
---|
314 | } |
---|
315 | // We need a node-context for token replacement. When on the Workflow tab |
---|
316 | // form, the node object will already have been loaded on the form. |
---|
317 | // When creating content (node/add/<type>) we only have limited data. In |
---|
318 | // the remaining cases we load the node from the cache based on the nid |
---|
319 | // found on the form. |
---|
320 | $form_id = $form['form_id']['#value']; |
---|
321 | if (strpos($form_id, 'workflow_tab_form') === 0) { |
---|
322 | $node = $form['node']['#value']; |
---|
323 | } |
---|
324 | elseif (is_numeric($nid = $form['nid']['#value'])) { |
---|
325 | $node = node_load($nid); |
---|
326 | } |
---|
327 | else { // Creating new content, nid not yet known |
---|
328 | $node = $form['#node']; |
---|
329 | } |
---|
330 | $states = $form['workflow'][$workflow_name]['#options']; |
---|
331 | $submit_handlers = _workflow_extensions_assign_handlers($form); |
---|
332 | foreach ($states as $sid => $to_state_name) { |
---|
333 | if ($sid != $current_sid) { |
---|
334 | // Create button for transition from current_sid to destination state. |
---|
335 | $button = array(); |
---|
336 | $button['#value'] = workflow_extensions_get_transition_label($form['#wf']->wid, $current_state_name, workflow_get_state_name($sid), $node); |
---|
337 | $button['#type'] = 'submit'; |
---|
338 | $button['#to_state'] = $sid; |
---|
339 | if (isset($form['buttons']['submit']['#weight'])) { // node form |
---|
340 | $button['#weight'] = $form['buttons']['submit']['#weight'] + 1; |
---|
341 | } |
---|
342 | elseif (isset($form['submit']['#weight'])) { // comment form |
---|
343 | $button['#weight'] = $form['submit']['#weight']; |
---|
344 | } |
---|
345 | $button['#submit'] = $submit_handlers; |
---|
346 | $form['buttons']["submit_to_$to_state_name"] = $button; |
---|
347 | } |
---|
348 | } |
---|
349 | // Get rid of workflow radio buttons that live inside the fieldset |
---|
350 | unset($form['workflow'][$workflow_name]); |
---|
351 | // If after this the fieldset is empty, remove it altogher |
---|
352 | if (!isset($form['workflow']['workflow_scheduled']) && |
---|
353 | (!isset($form['workflow']['workflow_comment']) || $form['workflow']['workflow_comment']['#type'] == 'hidden')) { |
---|
354 | unset($form['workflow']); |
---|
355 | } |
---|
356 | // With the existing Save button now impotent to submit a workflow |
---|
357 | // transition, we can re-purpose it for saving all other edits to the |
---|
358 | // node without changing the workflow state. |
---|
359 | // This does not make sense for the Workflow tab form though, as there is |
---|
360 | // nothing to save but a state change. In this case we simply remove the |
---|
361 | // Save button. |
---|
362 | if ($form_id == 'comment_form') { |
---|
363 | $form['buttons']['submit'] = $form['submit']; |
---|
364 | $form['buttons']['submit']['#submit'] = $form['#submit']; |
---|
365 | $form['buttons']['submit']['#weight']--; // left-most |
---|
366 | } |
---|
367 | if (strpos($form_id, 'workflow_tab_form') !== 0 && ($label = variable_get('workflow_extensions_default_save_button_label', ''))) { |
---|
368 | $form['buttons']['submit']['#value'] = workflow_extensions_replace_state_name_tokens($label, $current_state_name); |
---|
369 | } |
---|
370 | unset($form['submit']); // the button |
---|
371 | //unset($form['#submit']); // don't remove handler, [#1097328] |
---|
372 | } |
---|
373 | |
---|
374 | function _workflow_extensions_replace_with_dropdown(&$form, $workflow_name) { |
---|
375 | $form['workflow'][$workflow_name]['#type'] = 'select'; |
---|
376 | $form['workflow'][$workflow_name]['#name'] = 'workflow'; |
---|
377 | } |
---|
378 | |
---|
379 | /** |
---|
380 | * Implementation of hook_block(). |
---|
381 | */ |
---|
382 | function workflow_extensions_block($op = 'list', $delta = 0) { |
---|
383 | if (!module_exists('workflow')) { |
---|
384 | return; |
---|
385 | } |
---|
386 | if ($op == 'list') { |
---|
387 | $block[0]['info'] = t('Workflow state change form'); |
---|
388 | return $block; |
---|
389 | } |
---|
390 | elseif ($op == 'view' && arg(0) == 'node') { |
---|
391 | $node = node_load(arg(1)); |
---|
392 | $block['content'] = workflow_extensions_change_state_form($node); |
---|
393 | $block['subject'] = ''; |
---|
394 | return $block; |
---|
395 | } |
---|
396 | } |
---|
397 | |
---|
398 | /** |
---|
399 | * Use this function in a code-snippet to output a workflow state change form |
---|
400 | * on any page. May be used multiple times on the same page (for different |
---|
401 | * nodes), e.g. using the 'Views PHP' module, as a unique form_id is generated |
---|
402 | * for each occurrence of the form. |
---|
403 | * |
---|
404 | * @param $node |
---|
405 | */ |
---|
406 | function workflow_extensions_change_state_form($node) { |
---|
407 | |
---|
408 | if (!$node || !($wid = workflow_get_workflow_for_type($node->type))) { |
---|
409 | return ''; |
---|
410 | } |
---|
411 | |
---|
412 | $choices = workflow_field_choices($node); |
---|
413 | if (count($choices) == 1) { |
---|
414 | if (user_access('view workflow state change block even when state cannot be changed')) { |
---|
415 | // Generate single-option form without Submit button |
---|
416 | return drupal_get_form('workflow_extensions_single_state_form', workflow_get_name($wid), $choices); |
---|
417 | } |
---|
418 | return ''; // not allowed to view state |
---|
419 | } |
---|
420 | |
---|
421 | $result = db_query("SELECT sid, state FROM {workflow_states} WHERE status = 1 ORDER BY sid"); |
---|
422 | while ($row = db_fetch_object($result)) { |
---|
423 | $workflow_states[$row->sid] = check_plain(t($row->state)); |
---|
424 | } |
---|
425 | $sid_current = workflow_node_current_state($node); |
---|
426 | require_once drupal_get_path('module', 'workflow') . '/workflow.pages.inc'; |
---|
427 | $output = drupal_get_form('workflow_tab_form_nid_'. $node->nid, $node, $wid, $workflow_states, $sid_current); |
---|
428 | return $output; |
---|
429 | } |
---|
430 | |
---|
431 | /** |
---|
432 | * Form used to display the current state, without a submit button to change it. |
---|
433 | * @param $form_state |
---|
434 | * @param $workflow_name |
---|
435 | * @param $current_state, an array of one element, indexed by its sid |
---|
436 | */ |
---|
437 | function workflow_extensions_single_state_form($form_state, $workflow_name, $current_state) { |
---|
438 | $sids = array_keys($current_state); |
---|
439 | $form['workflow']['#title'] = $workflow_name; |
---|
440 | $form['workflow'][$workflow_name] = array( |
---|
441 | '#type' => 'radios', // may be overridden by workflow_extensions_form_alter() |
---|
442 | '#options' => $current_state, |
---|
443 | '#default_value' => $sids[0] |
---|
444 | ); |
---|
445 | return $form; |
---|
446 | } |
---|
447 | |
---|
448 | function workflow_extensions_extract_workflow_name($form) { |
---|
449 | // Current and allowed next states for this user and node live in |
---|
450 | // $form['workflow'][$workflow_name]['#options]. |
---|
451 | // At the time of writing, the workflow.module (6.x.1-4) contained a bug that |
---|
452 | // resulted in the $workflow_name being passed as blank. Luckily we can work |
---|
453 | // around this and also be compatible with later versions that don't have the |
---|
454 | // bug. |
---|
455 | if (isset($form['workflow'][''])) { |
---|
456 | return ''; |
---|
457 | } |
---|
458 | return isset($form['#wf']->name) ? $form['#wf']->name : $form['workflow']['#title']; |
---|
459 | } |
---|
460 | |
---|
461 | function _workflow_extensions_assign_handlers($form) { |
---|
462 | $original_handlers = $form['#submit']; // e.g. 'workflow_tab_form_submit' or 'menu_node_form_submit' |
---|
463 | return ($form['#id'] == 'node-form') // 'menu_node_form_submit', 'upload_node_form_submit' |
---|
464 | ? array('workflow_extensions_form_submit', 'node_form_submit') // node_form_submit() will add original handlers |
---|
465 | : array_merge(array('workflow_extensions_form_submit'), $original_handlers); |
---|
466 | |
---|
467 | // [#1346078] ? |
---|
468 | //$original_handlers = array_merge($original_handlers, $form['buttons']['submit']['#submit']); |
---|
469 | // return array_merge(array('workflow_extensions_form_submit'), $original_handlers); |
---|
470 | } |
---|
471 | |
---|
472 | /** |
---|
473 | * Implementation of hook_token_list(). |
---|
474 | * |
---|
475 | * Note: [workflow-new-state-name] is in fact a pseudo-token, but the user |
---|
476 | * doesn't have to know that! |
---|
477 | */ |
---|
478 | function workflow_extensions_token_list($context = 'all') { |
---|
479 | if (module_exists('workflow') && in_array($context, array('workflow', 'node', 'all'))) { |
---|
480 | $tokens['workflow']['workflow-new-state-name'] = 'New state of content'; |
---|
481 | $tokens['workflow']['workflow-state-age'] = 'Seconds elapsed since last state change'; |
---|
482 | } |
---|
483 | if ($context == 'node'|| $context == 'all') { |
---|
484 | $tokens['node']['mod-since-seconds'] = 'Seconds elapsed since last modification'; |
---|
485 | } |
---|
486 | return $tokens; |
---|
487 | } |
---|
488 | |
---|
489 | /** |
---|
490 | * Implementation of hook_token_values(). |
---|
491 | * |
---|
492 | * Returning [workflow-state-age] for both node and workflow contexts as there |
---|
493 | * seems to be an issue with using Workflow state as the data type argument in |
---|
494 | * a Rule set. Such a Rule set won't show as available in a scheduled triggered |
---|
495 | * rule. The Content (ie node) data type must be used instead. |
---|
496 | */ |
---|
497 | function workflow_extensions_token_values($context, $object = NULL) { |
---|
498 | $values = array(); |
---|
499 | switch ($context) { |
---|
500 | case 'node': |
---|
501 | case 'workflow': |
---|
502 | if (isset($object)) { |
---|
503 | $node = (object)$object; |
---|
504 | if (module_exists('workflow')) { |
---|
505 | $stamp = db_result(db_query_range("SELECT stamp FROM {workflow_node_history} WHERE nid = %d ORDER BY stamp DESC", $node->nid, 0, 1)); |
---|
506 | $values['workflow-state-age'] = $stamp ? (time() - $stamp) : 0; |
---|
507 | } |
---|
508 | $values['mod-since-seconds'] = $node->changed ? (time() - $node->changed) : 0; |
---|
509 | } |
---|
510 | break; |
---|
511 | } |
---|
512 | return $values; |
---|
513 | } |
---|
514 | |
---|
515 | /** |
---|
516 | * Return the name for the workflow transition identified by the supplied |
---|
517 | * from-state and to-state names. |
---|
518 | * |
---|
519 | * @param int $wid, workflow identifier, maybe NULL (but then the combination |
---|
520 | * of $from_state_name and $to_state_name must be unique across all workflows) |
---|
521 | * @param string $from_state_name |
---|
522 | * @param string $to_state_name |
---|
523 | * @param object $node, context for token replacement; if omitted an attempt |
---|
524 | * will be made to load the node based on the nid in the URL. This will fail |
---|
525 | * when creating new content, in which case a partial node must be supplied. |
---|
526 | */ |
---|
527 | function workflow_extensions_get_transition_label($wid, $from_state_name, $to_state_name, $node = NULL) { |
---|
528 | if (module_exists('workflow_named_transitions')) { |
---|
529 | $transitions = workflow_named_transitions_get_transitions($wid); |
---|
530 | foreach ($transitions as $transition) { |
---|
531 | if ($transition['from_state'] == $from_state_name && $transition['to_state'] == $to_state_name) { |
---|
532 | return workflow_extensions_replace_state_name_tokens($transition['label'], $to_state_name, $node); |
---|
533 | } |
---|
534 | } |
---|
535 | // No label defined, fall through as if module 'workflow_named_transitions' |
---|
536 | // wasn't installed |
---|
537 | } |
---|
538 | $tokenized_label = variable_get('workflow_extensions_change_state_button_label', ''); |
---|
539 | // Don't think we need to check_markup(). Only users with 'administer site |
---|
540 | // configuration' permission can set the label pattern, so it's up to them to |
---|
541 | // use or not use HTML and/or javascript. |
---|
542 | return workflow_extensions_replace_state_name_tokens($tokenized_label, $to_state_name, $node); |
---|
543 | } |
---|
544 | |
---|
545 | function workflow_extensions_replace_state_name_tokens($tokenized_label, $to_state_name = NULL, $node = NULL) { |
---|
546 | if (empty($tokenized_label)) { |
---|
547 | return t('Move to "@state_name"', array('@state_name' => $to_state_name)); |
---|
548 | } |
---|
549 | $label = workflow_extensions_replace_tokens_raw($tokenized_label, $node); |
---|
550 | if (!empty($to_state_name)) { |
---|
551 | // Once the real tokens have been replaced, replace the pseudo-token |
---|
552 | // [workflow-new-state-name] |
---|
553 | $label = str_replace('[workflow-new-state-name]', $to_state_name, $label); |
---|
554 | } |
---|
555 | return $label; |
---|
556 | } |
---|
557 | |
---|
558 | function workflow_extensions_replace_tokens_raw($tokenized_label, $node = NULL) { |
---|
559 | if (module_exists('token')) { |
---|
560 | global $user; |
---|
561 | $objects['global'] = NULL; |
---|
562 | $objects['user'] = $user; |
---|
563 | if ($node == NULL && arg(0) == 'node' && is_numeric(arg(1))) { |
---|
564 | $node = node_load(arg(1)); // node/% |
---|
565 | } |
---|
566 | $objects['node'] = $objects['workflow'] = $node; |
---|
567 | return token_replace_multiple($tokenized_label, $objects); |
---|
568 | } |
---|
569 | return $tokenized_label; |
---|
570 | } |
---|
571 | |
---|
572 | /** |
---|
573 | * Implementation of hook_views_api(). |
---|
574 | */ |
---|
575 | function workflow_extensions_views_api() { |
---|
576 | return array( |
---|
577 | 'api' => views_api_version(), |
---|
578 | 'path' => drupal_get_path('module', 'workflow_extensions') .'/views' |
---|
579 | ); |
---|
580 | } |
---|