1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * Allows the creation and modification of pre-published as well as live |
---|
6 | * content while the current revision remains unchanged and publicly visible |
---|
7 | * until the changes have been reviewed by a moderator. |
---|
8 | */ |
---|
9 | |
---|
10 | define('REVISIONING_LOAD_CURRENT', 0); // node/%node/view, node/%node/edit opens current revision |
---|
11 | define('REVISIONING_LOAD_LATEST', 1); // node/%node/view, node/%node/edit opens latest revison |
---|
12 | |
---|
13 | define('NEW_REVISION_WHEN_NOT_PENDING', 0); |
---|
14 | define('NEW_REVISION_EVERY_SAVE', 1); |
---|
15 | |
---|
16 | define('REVISIONS_BLOCK_OLDEST_AT_TOP', 0); |
---|
17 | define('REVISIONS_BLOCK_NEWEST_AT_TOP', 1); |
---|
18 | |
---|
19 | require_once drupal_get_path('module', 'revisioning') .'/revisioning_api.inc'; |
---|
20 | require_once drupal_get_path('module', 'revisioning') .'/revisioning.pages.inc'; |
---|
21 | require_once drupal_get_path('module', 'revisioning') .'/revisioning_theme.inc'; |
---|
22 | require_once drupal_get_path('module', 'revisioning') .'/revisioning_tokens.inc'; |
---|
23 | require_once drupal_get_path('module', 'revisioning') .'/revisioning_triggers_actions.inc'; |
---|
24 | // No need to include Rules integration file - Rules module does it for us automatically. |
---|
25 | |
---|
26 | /** |
---|
27 | * Implementation of hook_help(). |
---|
28 | */ |
---|
29 | function revisioning_help($path, $arg) { |
---|
30 | switch ($path) { |
---|
31 | case 'admin/help#revisioning': |
---|
32 | $s = t('For documentation and tutorials see the <a href="@revisioning">Revisioning project page</a>', |
---|
33 | array('@revisioning' => url('http://drupal.org/project/revisioning'))); |
---|
34 | break; |
---|
35 | case 'node/%/revisions': |
---|
36 | $s = t('To edit, publish or delete one of the revisions below, click on its saved date.'); |
---|
37 | break; |
---|
38 | case 'admin/build/trigger/revisioning': |
---|
39 | $s = t("Below you can assign actions to run when certain publication-related events happen. For example, you could send an e-mail to an author when their content is pubished."); |
---|
40 | break; |
---|
41 | case 'accessible-content/i-created/pending': |
---|
42 | $s = t('Showing all <em>pending</em> content <em>you created</em> and still have at least view access to.'); |
---|
43 | break; |
---|
44 | case 'accessible-content/i-last-modified/pending': |
---|
45 | $s = t('Showing all <em>pending</em> content <em>you last modified</em> and still have at least view access to.'); |
---|
46 | break; |
---|
47 | case 'accessible-content/i-can-edit/pending': |
---|
48 | $s = t('Showing all <em>pending</em> content you can <em>edit</em>.'); |
---|
49 | break; |
---|
50 | case 'accessible-content/i-can-view/pending': |
---|
51 | $s = t('Showing all <em>pending</em> content you have at least <em>view</em> access to.'); |
---|
52 | break; |
---|
53 | } |
---|
54 | return empty($s) ? '' : '<p>'. $s .'</p>'; |
---|
55 | } |
---|
56 | |
---|
57 | /** |
---|
58 | * Implementation of hook_perm(). |
---|
59 | * |
---|
60 | * Revisioning permissions. Note that permissions to view, revert and delete |
---|
61 | * revisions already exist in node.module. |
---|
62 | */ |
---|
63 | function revisioning_perm() { |
---|
64 | $perms = module_exists('module_grants_monitor') ? array('access Pending tab') : array(); |
---|
65 | $perms = array_merge($perms, array('view revision status messages', |
---|
66 | 'edit revisions', 'publish revisions', 'unpublish current revision')); |
---|
67 | // Add per node-type view perms in same way as edit perms of node module. |
---|
68 | // TOOD only do this for content types that have the "Create new revision" ticked |
---|
69 | foreach (node_get_types() as $type) { |
---|
70 | $name = check_plain($type->type); |
---|
71 | $perms[] = 'view revisions of own '. $name .' content'; |
---|
72 | $perms[] = 'view revisions of any '. $name .' content'; |
---|
73 | $perms[] = 'publish revisions of own '. $name .' content'; |
---|
74 | $perms[] = 'publish revisions of any '. $name .' content'; |
---|
75 | } |
---|
76 | return $perms; |
---|
77 | } |
---|
78 | |
---|
79 | /** |
---|
80 | * Implementation of hook_menu(). |
---|
81 | * |
---|
82 | * Define new menu items. |
---|
83 | * Existing menu items are modified through hook_menu_alter(). |
---|
84 | */ |
---|
85 | function revisioning_menu() { |
---|
86 | $items = array(); |
---|
87 | |
---|
88 | if (module_exists('module_grants_monitor')) { |
---|
89 | // Add a tab to the 'I created' tab (defined in module_grants_monitor.module) |
---|
90 | $items['accessible-content/i-created/pending'] = array( |
---|
91 | 'title' => 'In draft/Pending publication', |
---|
92 | 'page callback' => '_revisioning_show_pending_nodes', |
---|
93 | 'page arguments' => array('view', I_CREATED), |
---|
94 | 'access callback' => 'revisioning_user_all_access', |
---|
95 | 'access arguments' => array(array('access I Created tab', 'access Pending tab')), |
---|
96 | 'type' => MENU_LOCAL_TASK, |
---|
97 | 'weight' => -1 |
---|
98 | ); |
---|
99 | // Add a tab to the 'I last modified' tab |
---|
100 | $items['accessible-content/i-last-modified/pending'] = array( |
---|
101 | 'title' => 'In draft/Pending publication', |
---|
102 | 'page callback' => '_revisioning_show_pending_nodes', |
---|
103 | 'page arguments' => array('view', I_LAST_MODIFIED), |
---|
104 | 'access callback' => 'revisioning_user_all_access', |
---|
105 | 'access arguments' => array(array('access I Last Modified tab', 'access Pending tab')), |
---|
106 | 'type' => MENU_LOCAL_TASK, |
---|
107 | 'weight' => -1 |
---|
108 | ); |
---|
109 | // Add a tab to the 'I can edit' tab |
---|
110 | $items['accessible-content/i-can-edit/pending'] = array( |
---|
111 | 'title' => 'In draft/Pending publication', |
---|
112 | 'page callback' => '_revisioning_show_pending_nodes', |
---|
113 | 'page arguments' => array('update'), |
---|
114 | 'access callback' => 'revisioning_user_all_access', |
---|
115 | 'access arguments' => array(array('access I Can Edit tab', 'access Pending tab')), |
---|
116 | 'type' => MENU_LOCAL_TASK, |
---|
117 | 'weight' => -1 |
---|
118 | ); |
---|
119 | // Add a tab to the 'I can view' tab (defined in module_grants.module) |
---|
120 | $items['accessible-content/i-can-view/pending'] = array( |
---|
121 | 'title' => 'In draft/Pending publication', |
---|
122 | 'page callback' => '_revisioning_show_pending_nodes', |
---|
123 | 'page arguments' => array('view'), |
---|
124 | 'access callback' => 'revisioning_user_all_access', |
---|
125 | 'access arguments' => array(array('access I Can View tab', 'access Pending tab')), |
---|
126 | 'type' => MENU_LOCAL_TASK, |
---|
127 | 'weight' => -1 |
---|
128 | ); |
---|
129 | } |
---|
130 | |
---|
131 | // Callback (not a tab) to allow users to unpublish a node. |
---|
132 | // Note that is a node operation more so than a revision operation, but |
---|
133 | // we let _revisioning_node_revision_access() handle access anyway. |
---|
134 | $items['node/%node/unpublish'] = array( |
---|
135 | //'title' => t(Unpublish current revision'), |
---|
136 | 'page callback' => 'drupal_get_form', |
---|
137 | 'page arguments' => array('revisioning_unpublish_confirm', 1), |
---|
138 | 'access callback' => '_revisioning_node_revision_access', // _revisioning_node_access ? |
---|
139 | 'access arguments' => array('unpublish current revision', 1), |
---|
140 | 'type' => MENU_CALLBACK, |
---|
141 | ); |
---|
142 | |
---|
143 | // Revision tab local subtasks (i.e. secondary tabs), up to 7 of them: |
---|
144 | // view, edit, publish, unpublish, revert, delete and compare. |
---|
145 | // All revision operations 'node/%node/revisions/%vid/<op>' are defined as |
---|
146 | // local tasks (tabs) secondary to the primary 'node/%node/revisions' local |
---|
147 | // task (tab). |
---|
148 | // The tricky part is to always set "tab_parent", core does NOT figure this |
---|
149 | // out based on the URL. %vid is optional, see vid_to_arg(). |
---|
150 | // Note: the MENU_DEFAULT_LOCAL_TASK for 'node/%node/revisions' is defined in |
---|
151 | // function revisioning_menu_alter() |
---|
152 | |
---|
153 | // View revision local subtask |
---|
154 | $items['node/%node/revisions/%vid/view'] = array( |
---|
155 | 'title' => 'View', |
---|
156 | 'load arguments' => array(3), |
---|
157 | 'page callback' => '_revisioning_view_revision', |
---|
158 | 'page arguments' => array(1), |
---|
159 | 'access callback' => '_revisioning_node_revision_access', |
---|
160 | 'access arguments' => array('view revisions', 1), |
---|
161 | 'type' => MENU_LOCAL_TASK, |
---|
162 | 'weight' => -10, |
---|
163 | 'tab_parent' => 'node/%/revisions', |
---|
164 | ); |
---|
165 | // Edit revision local subtask |
---|
166 | $items['node/%node/revisions/%vid/edit'] = array( |
---|
167 | 'title' => 'Edit', |
---|
168 | 'load arguments' => array(3), |
---|
169 | 'page callback' => '_revisioning_edit_revision', |
---|
170 | 'page arguments' => array(1), |
---|
171 | 'access callback' => '_revisioning_node_revision_access', |
---|
172 | 'access arguments' => array('edit revisions', 1), |
---|
173 | 'file' => 'node.pages.inc', |
---|
174 | 'file path' => drupal_get_path('module', 'node'), |
---|
175 | 'type' => MENU_LOCAL_TASK, |
---|
176 | 'weight' => -7, |
---|
177 | 'tab_parent' => 'node/%/revisions', |
---|
178 | ); |
---|
179 | // Publish revision local subtask |
---|
180 | $items['node/%node/revisions/%vid/publish'] = array( |
---|
181 | 'title' => 'Publish this', |
---|
182 | 'load arguments' => array(3), |
---|
183 | 'page callback' => 'drupal_get_form', |
---|
184 | 'page arguments' => array('revisioning_publish_confirm', 1), |
---|
185 | 'access callback' => '_revisioning_node_revision_access', |
---|
186 | 'access arguments' => array('publish revisions', 1), |
---|
187 | 'type' => MENU_LOCAL_TASK, |
---|
188 | 'weight' => -4, |
---|
189 | 'tab_parent' => 'node/%/revisions', |
---|
190 | ); |
---|
191 | // Unpublish node local subtask |
---|
192 | $items['node/%node/revisions/%vid/unpublish'] = array( |
---|
193 | 'title' => 'Unpublish this', |
---|
194 | 'load arguments' => array(3), |
---|
195 | 'page callback' => 'drupal_get_form', |
---|
196 | 'page arguments' => array('revisioning_unpublish_confirm', 1), |
---|
197 | 'access callback' => '_revisioning_node_revision_access', |
---|
198 | 'access arguments' => array('unpublish current revision', 1), |
---|
199 | 'type' => MENU_LOCAL_TASK, |
---|
200 | 'weight' => -3, |
---|
201 | 'tab_parent' => 'node/%/revisions', |
---|
202 | ); |
---|
203 | // Revert to revision local subtask. |
---|
204 | // Difference from core version is %vid that's served by vid_to_arg() function. |
---|
205 | $items['node/%node/revisions/%vid/revert'] = array( |
---|
206 | 'title' => 'Revert to this', |
---|
207 | 'load arguments' => array(3), |
---|
208 | 'page callback' => 'drupal_get_form', |
---|
209 | 'page arguments' => array('node_revision_revert_confirm', 1), |
---|
210 | 'access callback' => '_revisioning_node_revision_access', |
---|
211 | 'access arguments' => array('revert revisions', 1), |
---|
212 | 'file' => 'node.pages.inc', |
---|
213 | 'file path' => drupal_get_path('module', 'node'), |
---|
214 | 'type' => MENU_LOCAL_TASK, |
---|
215 | 'weight' => -2, |
---|
216 | 'tab_parent' => 'node/%/revisions', |
---|
217 | ); |
---|
218 | // Delete revision local subtask. |
---|
219 | // Difference from core version is %vid that's served by vid_to_arg() function. |
---|
220 | $items['node/%node/revisions/%vid/delete'] = array( |
---|
221 | 'title' => 'Delete', |
---|
222 | 'load arguments' => array(3), |
---|
223 | 'page callback' => 'drupal_get_form', |
---|
224 | 'page arguments' => array('node_revision_delete_confirm', 1), |
---|
225 | 'access callback' => '_revisioning_node_revision_access', |
---|
226 | 'access arguments' => array('delete revisions', 1), |
---|
227 | 'file' => 'node.pages.inc', |
---|
228 | 'file path' => drupal_get_path('module', 'node'), |
---|
229 | 'type' => MENU_LOCAL_TASK, |
---|
230 | 'weight' => 10, |
---|
231 | 'tab_parent' => 'node/%/revisions', |
---|
232 | ); |
---|
233 | |
---|
234 | // If Diff module is enabled, provide a compare local subtask |
---|
235 | if (module_exists('diff')) { |
---|
236 | $items['node/%node/revisions/%vid/compare'] = array( |
---|
237 | 'title' => 'Compare to current', |
---|
238 | 'load arguments' => array(3), |
---|
239 | 'page callback' => '_revisioning_compare_to_current_revision', |
---|
240 | 'page arguments' => array(1), |
---|
241 | 'access callback' => '_revisioning_node_revision_access', |
---|
242 | 'access arguments' => array('compare to current', 1), |
---|
243 | 'type' => MENU_LOCAL_TASK, |
---|
244 | 'weight' => 0, |
---|
245 | 'tab_parent' => 'node/%/revisions', |
---|
246 | ); |
---|
247 | } |
---|
248 | |
---|
249 | // Finally, the Revisioning configuration menu item |
---|
250 | $items['admin/settings/revisioning'] = array( |
---|
251 | 'title' => 'Revisioning', |
---|
252 | 'description' => 'Configure how links to view and edit content behave.', |
---|
253 | 'page callback' => 'drupal_get_form', |
---|
254 | 'page arguments' => array('revisioning_admin_configure'), |
---|
255 | 'access arguments' => array('administer site configuration'), |
---|
256 | 'file' => 'revisioning.admin.inc' |
---|
257 | ); |
---|
258 | |
---|
259 | return $items; |
---|
260 | } |
---|
261 | |
---|
262 | /** |
---|
263 | * Implementation of hook_menu_alter(). |
---|
264 | * |
---|
265 | * Modify menu items defined in other modules (in particular the Node and |
---|
266 | * Module Grants modules). |
---|
267 | */ |
---|
268 | function revisioning_menu_alter(&$items) { |
---|
269 | |
---|
270 | // Primary tabs for 'node/%node': View tab, Edit tab, Revisions tab ... |
---|
271 | |
---|
272 | // View tab can be either 'View current' or 'View latest'. |
---|
273 | // It should be suppressed when the 'Revisions' tab shows the same revision, |
---|
274 | // so we need a special access callback for this, which expands on the |
---|
275 | // callback defined in Module Grants. |
---|
276 | $items['node/%node']['access callback'] = $items['node/%node/view']['access callback'] = '_revisioning_view_edit_access_callback'; |
---|
277 | $items['node/%node']['access arguments']= $items['node/%node/view']['access arguments']= array('view', 1); |
---|
278 | $items['node/%node']['page callback'] = $items['node/%node/view']['page callback'] = '_revisioning_view'; |
---|
279 | $items['node/%node']['page arguments'] = $items['node/%node/view']['page arguments'] = array(1); |
---|
280 | // Not applying title callback to 'node/%node', see #782316 |
---|
281 | $items['node/%node/view']['title callback'] = '_revisioning_title_for_tab'; |
---|
282 | $items['node/%node/view']['title arguments'] = array(1, FALSE); |
---|
283 | |
---|
284 | // Edit tab can be either 'Edit current' or 'Edit latest'. |
---|
285 | // It should be suppressed when the 'Revisions' tab shows the same revision, |
---|
286 | // so we need a special access callback for this, which expands on the |
---|
287 | // callback defined in Module Grants. |
---|
288 | $items['node/%node/edit']['access callback'] = '_revisioning_view_edit_access_callback'; |
---|
289 | $items['node/%node/edit']['access arguments']= array('edit', 1); |
---|
290 | $items['node/%node/edit']['page callback'] = '_revisioning_edit'; |
---|
291 | $items['node/%node/edit']['title callback'] = '_revisioning_title_for_tab'; |
---|
292 | $items['node/%node/edit']['title arguments'] = array(1, TRUE); |
---|
293 | |
---|
294 | // 'Revisions' tab remains but points to new page callback, allowing users to |
---|
295 | // pick the revision to view, edit, publish, revert, unpublish, delete. |
---|
296 | // Need to override _node_revision_access() call back as it disallows access |
---|
297 | // to the 'Revisions' tab when there's only one revision, which will prevent |
---|
298 | // users from getting to the publish/unpublish links. |
---|
299 | $items['node/%node/revisions']['access callback'] = '_revisioning_node_revision_access'; |
---|
300 | $items['node/%node/revisions']['access arguments'] = array('view revision list', 1); |
---|
301 | $items['node/%node/revisions']['page callback'] = '_revisioning_present_node'; |
---|
302 | $items['node/%node/revisions']['page arguments'] = array(1); |
---|
303 | |
---|
304 | // Unset old menu items defined in node.module (or module_grants.module), as |
---|
305 | // these are replaced by ones that use the %vid wildcard instead of % and |
---|
306 | // come with the appropriate callbacks. |
---|
307 | unset($items['node/%node/revisions/%/view']); |
---|
308 | unset($items['node/%node/revisions/%/revert']); |
---|
309 | unset($items['node/%node/revisions/%/delete']); |
---|
310 | |
---|
311 | if (module_exists('diff')) { |
---|
312 | // If Diff module is enabled, make sure it uses correct access callback |
---|
313 | $items['node/%node/revisions/view/%/%']['access callback'] = '_revisioning_node_revision_access'; |
---|
314 | $items['node/%node/revisions/view/%/%']['access arguments'] = array('view revisions', 1); |
---|
315 | } |
---|
316 | // This is here rather than in revisioning_menu() as Diff may redefine |
---|
317 | // the node/%node/revisions/list item. |
---|
318 | $items['node/%node/revisions/list'] = array( |
---|
319 | 'title' => t('List all revisions'), |
---|
320 | 'access callback' => '_revisioning_node_revision_access', |
---|
321 | 'access arguments' => array('view revision list', 1), |
---|
322 | 'file' => 'node.pages.inc', |
---|
323 | 'module' => 'node', |
---|
324 | //'file path' => drupal_get_path('module', 'node'), |
---|
325 | 'type' => MENU_LOCAL_TASK, // was: MENU_DEFAULT_LOCAL_TASK; changed for Smart tabs |
---|
326 | 'weight' => -20, |
---|
327 | ); |
---|
328 | |
---|
329 | $items['node/%node/revisions/delete-archived'] = array( |
---|
330 | 'title' => t('Delete archived revisions'), |
---|
331 | 'page callback' => 'drupal_get_form', |
---|
332 | 'page arguments' => array('revisioning_delete_archived_confirm', 1), |
---|
333 | 'access callback' => '_revisioning_node_revision_access', |
---|
334 | 'access arguments' => array('delete archived revisions', 1), |
---|
335 | 'type' => MENU_CALLBACK, |
---|
336 | ); |
---|
337 | |
---|
338 | // Apart from administrators, allow those that pass the 'trigger_access_check' |
---|
339 | // to configure the revisioning triggers. This means that users must have at |
---|
340 | // least 'administer actions' and 'access administration pages' (the latter is |
---|
341 | // to allow them to navigate to the trigger page via the menu). |
---|
342 | if (module_exists('trigger')) { |
---|
343 | $items['admin/build/trigger/revisioning']['access callback'] = 'trigger_access_check'; |
---|
344 | } |
---|
345 | |
---|
346 | // [#1024864]: Allow other modules to make further alterations |
---|
347 | drupal_alter('revisioning_menu', $items); |
---|
348 | } |
---|
349 | |
---|
350 | /** |
---|
351 | * Implementation of hook_nodeapi(). |
---|
352 | * |
---|
353 | * This function is called serveral times during the node's life cycle, with |
---|
354 | * different node operations passed in. |
---|
355 | * |
---|
356 | * Typically when loading a node for viewing, the order is: |
---|
357 | * 'load', 'view', 'alter' |
---|
358 | * |
---|
359 | * When creating new content: |
---|
360 | * Before displaying the creation form: 'prepare' |
---|
361 | * When saving: 'validate', 'presave', 'insert' |
---|
362 | * |
---|
363 | * When editing an existing node: |
---|
364 | * Before displaying the edit form: 'load', 'prepare' |
---|
365 | * When saving: 'load', 'validate', 'presave', 'update' |
---|
366 | * |
---|
367 | * The same $op may be requested multiple times during the same HTTP request, |
---|
368 | * especially 'load'. |
---|
369 | */ |
---|
370 | function revisioning_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { |
---|
371 | if (!empty($node->bypass_nodeapi)) { |
---|
372 | return; |
---|
373 | } |
---|
374 | |
---|
375 | switch ($op) { |
---|
376 | case 'load': // called at the end of node_load() |
---|
377 | // The revision_moderation flag may be overridden on the node edit form |
---|
378 | // by users with the "administer nodes" permission |
---|
379 | $node->revision_moderation = node_tools_content_is_moderated($node->type); |
---|
380 | $node->is_pending = _revisioning_node_is_pending($node); |
---|
381 | |
---|
382 | // Could use following, but this seems old style, i.e. when $node is not a &ref |
---|
383 | //$node_extras['revision_moderation'] = $node->revision_moderation; |
---|
384 | //$node_extras['is_pending'] = $node->is_pending; |
---|
385 | break; |
---|
386 | |
---|
387 | case 'view': // called from called from node_view() before $node is fully built |
---|
388 | break; |
---|
389 | |
---|
390 | case 'alter': // called from node_view() after $node is fully built for display |
---|
391 | if (!$teaser && $node->nid == arg(1) && // don't show msg on page with many nodes |
---|
392 | !empty($node->revision_moderation) && user_access('view revision status messages')) { |
---|
393 | drupal_set_message(_revisioning_node_info_msg($node)); |
---|
394 | } |
---|
395 | break; |
---|
396 | |
---|
397 | case 'prepare': // presenting edit form |
---|
398 | // Check that we're dealing with the current node, not its translation source |
---|
399 | $current_nid = arg(1); |
---|
400 | if (is_numeric($current_nid) && $current_nid == $node->nid) { |
---|
401 | _revisioning_prepare_msg($node); |
---|
402 | } |
---|
403 | break; |
---|
404 | |
---|
405 | case 'presave': // for edits, called from node_save(), prior to _node_save_revision() |
---|
406 | if (!empty($node->revision_moderation)) { // Tick-box on edit form |
---|
407 | $node->is_pending = _revisioning_node_is_pending($node); |
---|
408 | if ($node->revision && $node->is_pending && variable_get('new_revisions_'. $node->type, NEW_REVISION_WHEN_NOT_PENDING) == NEW_REVISION_WHEN_NOT_PENDING) { |
---|
409 | drupal_set_message(t('Updating existing copy, not creating new revision as this one is still pending.')); |
---|
410 | // Update the $node object just before it is saved to the db |
---|
411 | $node->revision = FALSE; |
---|
412 | } |
---|
413 | // Save title of current revision to restore at $op=='update' time |
---|
414 | $node->current_title = db_result(db_query('SELECT title FROM {node} WHERE nid=%d', $node->nid)); |
---|
415 | |
---|
416 | if (variable_get('revisioning_auto_publish_'. $node->type, FALSE)) { |
---|
417 | if (user_access('publish revisions') || |
---|
418 | user_access("publish revisions of any $node->type content") || |
---|
419 | (user_access("publish revisions of own $node->type content") && $node->revision_uid == $user->uid)) { |
---|
420 | if (!$node->status) { |
---|
421 | // Fix for [#751092] (thanks naquah and mirgorod_a). |
---|
422 | // If the Publish box has just been unticked, do not auto-publish. |
---|
423 | if (isset($node->nid)) { |
---|
424 | // Existing published node for which Publish box was unticked. |
---|
425 | if (db_result(db_query("SELECT status FROM {node} WHERE nid = %d", $node->nid))) { |
---|
426 | break; |
---|
427 | } |
---|
428 | } |
---|
429 | else { |
---|
430 | $node_options = variable_get('node_options_'. $node->type, array()); |
---|
431 | if (in_array('status', $node_options)) { |
---|
432 | // New node for which Publish box is ticked by default but was |
---|
433 | // unticked on the edit form. |
---|
434 | break; |
---|
435 | } |
---|
436 | } |
---|
437 | } |
---|
438 | drupal_set_message(t('Auto-publishing this revision.')); |
---|
439 | $node->status = TRUE; |
---|
440 | // Make sure the 'update' does NOT reset vid, so that new revision becomes current |
---|
441 | unset($node->current_revision_id); |
---|
442 | } |
---|
443 | } |
---|
444 | } |
---|
445 | break; |
---|
446 | |
---|
447 | case 'insert': // new node, called from node_save(), after _node_save_revision() |
---|
448 | if (!empty($node->revision_moderation)) { |
---|
449 | _revisioning_insert_msg($node); |
---|
450 | } |
---|
451 | break; |
---|
452 | |
---|
453 | case 'update': // edited node, called from node_save(), after _node_save_revision() |
---|
454 | if (!empty($node->revision_moderation) && $node->current_revision_id // i.e. set and not 0 |
---|
455 | && $node->current_revision_id != $node->vid) { |
---|
456 | // Resetting title and vid back to their originial values, thus creating pending revision. |
---|
457 | db_query("UPDATE {node} SET vid=%d, title='%s' WHERE nid=%d", $node->current_revision_id, $node->current_title, $node->nid); |
---|
458 | //$node->is_pending = TRUE; |
---|
459 | } |
---|
460 | break; |
---|
461 | |
---|
462 | case 'delete revision': |
---|
463 | module_invoke_all('revisionapi', 'post delete', $node); |
---|
464 | break; |
---|
465 | } |
---|
466 | } |
---|
467 | |
---|
468 | /** |
---|
469 | * Implementation of hook_block(). |
---|
470 | * |
---|
471 | * A block that may be placed on all or selected pages, alerting the user |
---|
472 | * (moderator) when new content has been submitted for review. Shows titles |
---|
473 | * of pending revisions as a series of links (max. number configurable). |
---|
474 | * Clicking a link takes the moderator straight to the revision in question. |
---|
475 | */ |
---|
476 | function revisioning_block($op = 'list', $delta = 0, $edit = array()) { |
---|
477 | switch ($op) { |
---|
478 | case 'list': |
---|
479 | // Set up the defaults for the Site configuration>>Blocks page |
---|
480 | // Return a list of (1) block(s) and the default values |
---|
481 | $blocks[0]['info'] = t('Pending revisions'); |
---|
482 | $blocks[0]['cache'] = BLOCK_NO_CACHE; |
---|
483 | $blocks[0]['weight'] = -10; // top of whatever region is chosen |
---|
484 | $blocks[0]['custom'] = FALSE; // block is implemented by this module; |
---|
485 | return $blocks; |
---|
486 | |
---|
487 | case 'configure': |
---|
488 | $form['revisioning_block_num_pending'] = array( |
---|
489 | '#type' => 'textfield', |
---|
490 | '#title' => t('Maximum number of pending revisions displayed'), |
---|
491 | '#default_value' => variable_get('revisioning_block_num_pending', 5), |
---|
492 | '#description' => t('Note: the title of this block mentions the total number of revisions pending, which may be greater than the number of revisions displayed.') |
---|
493 | ); |
---|
494 | $form['revisioning_block_order'] = array( |
---|
495 | '#type' => 'radios', |
---|
496 | '#title' => t('Order in which pending revisions are displayed'), |
---|
497 | '#options' => array( |
---|
498 | REVISIONS_BLOCK_OLDEST_AT_TOP => t('Oldest at top'), |
---|
499 | REVISIONS_BLOCK_NEWEST_AT_TOP => t('Newest at top')), |
---|
500 | '#default_value' => variable_get('revisioning_block_order', REVISIONS_BLOCK_OLDEST_AT_TOP), |
---|
501 | '#description' => t('Note: order is based on revision timestamps.') |
---|
502 | ); |
---|
503 | $form['revisioning_content_summary_page'] = array( |
---|
504 | '#type' => 'textfield', |
---|
505 | '#title' => t('Page to go to when the block title is clicked'), |
---|
506 | '#default_value' => variable_get('revisioning_content_summary_page', ''), |
---|
507 | '#description' => t('When left blank this will default to %accessible_content, provided Module Grants Montior is enabled and the user has sufficient permissions. Otherwise %admin_content is used, subject to permissions. For any of this to work the above <strong>Block title</strong> field must be left blank.', |
---|
508 | array('%accessible_content' => 'accessible-content', '%admin_content' => 'admin/content/node')) |
---|
509 | ); |
---|
510 | return $form; |
---|
511 | |
---|
512 | case 'save': |
---|
513 | variable_set('revisioning_block_num_pending', (int)$edit['revisioning_block_num_pending']); |
---|
514 | variable_set('revisioning_block_order', (int)$edit['revisioning_block_order']); |
---|
515 | variable_set('revisioning_content_summary_page', $edit['revisioning_content_summary_page']); |
---|
516 | break; |
---|
517 | |
---|
518 | case 'view': |
---|
519 | $max_nodes = variable_get('revisioning_block_num_pending', 100); |
---|
520 | $order = variable_get('revisioning_block_order', REVISIONS_BLOCK_OLDEST_AT_TOP) == REVISIONS_BLOCK_OLDEST_AT_TOP ? 'ASC' : 'DESC'; |
---|
521 | $nodes = node_tools_get_nodes('update', NO_FILTER, NO_FILTER, NO_FILTER, TRUE, TRUE, $max_nodes, 'timestamp '. $order); |
---|
522 | if (!empty($nodes)) { |
---|
523 | return _theme_revisions_pending_block($nodes); |
---|
524 | } |
---|
525 | } |
---|
526 | } |
---|
527 | |
---|
528 | /** |
---|
529 | * Implementation of hook_views_api(). |
---|
530 | */ |
---|
531 | function revisioning_views_api() { |
---|
532 | return array( |
---|
533 | 'api' => views_api_version(), |
---|
534 | 'path' => drupal_get_path('module', 'revisioning') .'/views' |
---|
535 | ); |
---|
536 | } |
---|
537 | |
---|
538 | /** |
---|
539 | * Perform path manipulations for menu items containing %vid wildcard. $map |
---|
540 | * contains what arg() function returns, eg. $map[0]=='node', $map[1]=='123'. |
---|
541 | * |
---|
542 | * When vid is absent, return $map as empty array. This seems to disable menu |
---|
543 | * items which require a vid context to work. So on the page |
---|
544 | * "node/123/revisions" we won't see tasks like "node/123/revisions/456/edit". |
---|
545 | * |
---|
546 | * An alternative implementation would be to substitute an empty vid with |
---|
547 | * current revision id. In that case we should also change the tab titles |
---|
548 | * (via title callbacks) for an enhanced user experience. For example: we'd |
---|
549 | * change "Edit" to "Edit current". |
---|
550 | * |
---|
551 | * See http://drupal.org/node/500864 |
---|
552 | */ |
---|
553 | function vid_to_arg($arg, &$map, $index) { |
---|
554 | if (empty($arg)) { |
---|
555 | //return node_tools_get_current_node_revision_id($nid = $map[1]); |
---|
556 | $map = array(); |
---|
557 | return ''; |
---|
558 | } |
---|
559 | return $arg; |
---|
560 | } |
---|
561 | |
---|
562 | /** |
---|
563 | * Implementation of hook_user_node_access(). |
---|
564 | * |
---|
565 | * @see module_grants_node_revision_access() |
---|
566 | * |
---|
567 | * @param $revision_op |
---|
568 | * node or revision operation e.g. 'view revisions' |
---|
569 | * @param $node |
---|
570 | * @return the associated node operation required for this revision_op, or |
---|
571 | * FALSE if access to the node is to be denied. |
---|
572 | * Valid node operations to return are 'view', 'update', 'delete'. |
---|
573 | */ |
---|
574 | function revisioning_user_node_access($revision_op, $node) { |
---|
575 | global $user; |
---|
576 | |
---|
577 | $type = check_plain($node->type); |
---|
578 | |
---|
579 | switch ($revision_op) { |
---|
580 | case 'view current': |
---|
581 | break; |
---|
582 | case 'compare to current': |
---|
583 | case 'view revisions': |
---|
584 | case 'view revision list': |
---|
585 | if (user_access('view revisions', $user)) { // node.module |
---|
586 | break; |
---|
587 | } |
---|
588 | if (user_access('view revisions of any '. $type .' content', $user)) { |
---|
589 | break; |
---|
590 | } |
---|
591 | if (($node->uid == $user->uid) && user_access('view revisions of own '. $type .' content', $user)) { |
---|
592 | break; |
---|
593 | } |
---|
594 | return FALSE; |
---|
595 | |
---|
596 | case 'edit current': |
---|
597 | return 'update'; |
---|
598 | |
---|
599 | case 'edit revisions': |
---|
600 | case 'revert revisions': |
---|
601 | return user_access($revision_op, $user) ? 'update' : FALSE; |
---|
602 | |
---|
603 | case 'publish revisions': |
---|
604 | if (user_access('publish revisions of any '. $type .' content', $user)) { |
---|
605 | break; |
---|
606 | } |
---|
607 | if (($node->uid == $user->uid) && user_access('publish revisions of own '. $type .' content', $user)) { |
---|
608 | break; |
---|
609 | } |
---|
610 | case 'unpublish current revision': |
---|
611 | return user_access($revision_op, $user) ? 'view' : FALSE; |
---|
612 | |
---|
613 | case 'delete revisions': |
---|
614 | case 'delete archived revisions': |
---|
615 | if (!user_access('delete revisions', $user)) { |
---|
616 | return FALSE; |
---|
617 | } |
---|
618 | case 'delete node': |
---|
619 | return 'delete'; |
---|
620 | |
---|
621 | default: |
---|
622 | drupal_set_message(t("Unknown Revisioning operation '%op'. Treating as 'view'.", array('%op' => $revision_op)), 'warning', FALSE); |
---|
623 | } |
---|
624 | return 'view'; |
---|
625 | } |
---|
626 | |
---|
627 | /** |
---|
628 | * Test whether the supplied revision operation is appropriate for the node. |
---|
629 | * This is irrespective of user permissions, e.g. even for an administrator it |
---|
630 | * doesn't make sense to publish a node that is already published or to |
---|
631 | * "revert" to the current revision. |
---|
632 | * |
---|
633 | * @param $revision_op |
---|
634 | * @param $node |
---|
635 | * @return TRUE if the operation is appropriate for this node at this point |
---|
636 | */ |
---|
637 | function _revisioning_operation_appropriate($revision_op, $node) { |
---|
638 | switch ($revision_op) { |
---|
639 | |
---|
640 | case 'compare to current': |
---|
641 | // Can't compare against itself |
---|
642 | case 'delete revisions': |
---|
643 | // If the revision is the current one, suppress the delete operation |
---|
644 | // @TODO ...unless it's the only revision, in which case delete the |
---|
645 | // entire node; however this requires a different URL. |
---|
646 | return !$node->is_current; |
---|
647 | |
---|
648 | case 'delete archived revisions': |
---|
649 | break; |
---|
650 | |
---|
651 | case 'view revision list': // i.e. node revisions summary |
---|
652 | if ($node->num_revisions == 1 && !$node->revision_moderation |
---|
653 | /* && (module_exists('module_grants') ? !module_grants_node_access('delete', $node) : !node_access('delete', $node))*/) { |
---|
654 | // Suppress Revisions tab when when there's only 1 revision -- consistent with core. |
---|
655 | // However, when content is moderated (i.e. "New revision in draft, |
---|
656 | // pending moderation" is ticked) we want to be able to get to the |
---|
657 | // 'Unpublish current' link on this page and the 'Publish this' tab on |
---|
658 | // the next. Also when user has permission to delete node, we need to |
---|
659 | // present the Delete link, unless we assume that this privilege |
---|
660 | // assumes the 'edit' permission. |
---|
661 | return FALSE; |
---|
662 | } |
---|
663 | break; |
---|
664 | |
---|
665 | case 'publish revisions': |
---|
666 | // If the node isn't meant to be moderated and the user is not an admin, |
---|
667 | // or the revision is not either pending or current but not published, |
---|
668 | // then disallow publication. |
---|
669 | if ((!$node->revision_moderation && !user_access('administer nodes')) |
---|
670 | || !($node->is_pending || ($node->is_current && !$node->status))) { |
---|
671 | return FALSE; |
---|
672 | } |
---|
673 | break; |
---|
674 | |
---|
675 | case 'unpublish current revision': |
---|
676 | // If the node isn't meant to be moderated and the user is not an admin, |
---|
677 | // or it is unpublished already or we're not looking at the current |
---|
678 | // revision, then unpublication is not an option. |
---|
679 | if ((!$node->revision_moderation && !user_access('administer nodes')) |
---|
680 | || !$node->status || !$node->is_current) { |
---|
681 | return FALSE; |
---|
682 | } |
---|
683 | break; |
---|
684 | |
---|
685 | case 'revert revisions': |
---|
686 | // If this revision is pending or current, suppress the reversion |
---|
687 | if ($node->is_pending || $node->is_current) { |
---|
688 | return FALSE; |
---|
689 | } |
---|
690 | break; |
---|
691 | } |
---|
692 | return TRUE; |
---|
693 | } |
---|
694 | |
---|
695 | /** |
---|
696 | * Determine whether the supplied revision operation is permitted on the node. |
---|
697 | * This requires getting through three levels of defence: |
---|
698 | * o Is the operation appropriate for this node at this time, e.g. a node must |
---|
699 | * not be published if it already is or if it isn't under moderation control |
---|
700 | * o Does the user have permissions to operations of this kind in general? |
---|
701 | * o Does the user have the node access rights (view/update/delete) required |
---|
702 | * for this operation? |
---|
703 | * |
---|
704 | * @param $revision_op |
---|
705 | * For instance 'publish revisions', 'delete revisions' |
---|
706 | * @param $node |
---|
707 | * @return bool |
---|
708 | */ |
---|
709 | function _revisioning_node_revision_access($revision_op, $node) { |
---|
710 | |
---|
711 | if (!isset($node->num_revisions) || !isset($node->is_current)) { |
---|
712 | drupal_set_message(t('Node object data incomplete -- have you enabled the Node Tools submodule?'), 'warning', FALSE); |
---|
713 | } |
---|
714 | if (!_revisioning_operation_appropriate($revision_op, $node)) { |
---|
715 | return FALSE; |
---|
716 | } |
---|
717 | if (module_exists('module_grants')) { |
---|
718 | $access = module_grants_node_revision_access($revision_op, $node); |
---|
719 | } |
---|
720 | else { |
---|
721 | // Fall back to core to assess permissions (even though they suck) |
---|
722 | $access = ($node_op = revisioning_user_node_access($revision_op, $node)) && |
---|
723 | node_access($node_op, $node); |
---|
724 | } |
---|
725 | return $access; |
---|
726 | } |
---|
727 | |
---|
728 | /** |
---|
729 | * Access callback for 'node/%', 'node/%/view' and 'node/%/edit' links that |
---|
730 | * may appear anywhere on the site. |
---|
731 | * At the time that this function is called the CURRENT revision will already |
---|
732 | * have been loaded by the system. However depending on the value of the |
---|
733 | * 'revisioning_view_callback' and 'revisioning_edit_callback' variables (as |
---|
734 | * set on the admin/settings/revisioning page), this may not be the desired |
---|
735 | * revision. |
---|
736 | * If these variables state that the LATEST revision should be loaded, we need |
---|
737 | * to check at this point whether the user has permission to view this revision. |
---|
738 | * |
---|
739 | * The 'View current' and/or 'Edit current' tabs are suppressed when the current |
---|
740 | * revision is already displayed via one of the Revisions subtabs. |
---|
741 | * The 'View latest' and/or 'Edit latest' tabs are suppressed when the latest |
---|
742 | * revision is already displayed via one of the Revisions subtabs. |
---|
743 | * |
---|
744 | * @param op, must be one of 'view' or 'edit' |
---|
745 | * @param $node |
---|
746 | * @return FALSE if access to the desired revision is denied |
---|
747 | * |
---|
748 | */ |
---|
749 | function _revisioning_view_edit_access_callback($op, $node) { |
---|
750 | |
---|
751 | $load_op = _revisioning_load_op($node, $op); |
---|
752 | |
---|
753 | $vid = arg(3); |
---|
754 | if (/*!empty($node->revision_moderation) && */is_numeric($vid)) { |
---|
755 | // The View, Edit primary tabs are requested indirectly, in the context of |
---|
756 | // the secondary tabs under Revisions, e.g. node/%/revisions/% |
---|
757 | if ($load_op == REVISIONING_LOAD_CURRENT && $vid == $node->current_revision_id) { |
---|
758 | // Suppress 'View current' and 'Edit current' primary tabs when viewing current |
---|
759 | return FALSE; |
---|
760 | } |
---|
761 | if ($load_op == REVISIONING_LOAD_LATEST && $vid == revisioning_get_latest_revision_id($node->nid)) { |
---|
762 | // Suppress 'View latest' and 'Edit latest' primary tabs when viewing latest |
---|
763 | return FALSE; |
---|
764 | } |
---|
765 | } |
---|
766 | if ($load_op == REVISIONING_LOAD_LATEST) { |
---|
767 | // _revisioning_load_op has already checked permission to view latest |
---|
768 | return TRUE; |
---|
769 | } |
---|
770 | $revision_op = ($op == 'view') ? 'view current' : 'edit current'; |
---|
771 | return _revisioning_node_revision_access($revision_op, $node); |
---|
772 | } |
---|
773 | |
---|
774 | function _revisioning_load_op($node, $op, $check_access = TRUE) { |
---|
775 | if ($node->revision_moderation) { |
---|
776 | $view_mode = (int)variable_get('revisioning_view_callback', REVISIONING_LOAD_CURRENT); |
---|
777 | $edit_mode = (int)variable_get('revisioning_edit_callback', REVISIONING_LOAD_CURRENT); |
---|
778 | $load_op = ($op == 'edit') ? $edit_mode : $view_mode; |
---|
779 | if ($load_op == REVISIONING_LOAD_LATEST) { |
---|
780 | // Site is configured to load latest revision, but we'll only do this if |
---|
781 | // the latest isn't loaded already and the user has the permission to do so. |
---|
782 | $latest_vid = revisioning_get_latest_revision_id($node->nid); |
---|
783 | if ($latest_vid != $node->current_revision_id) { |
---|
784 | if (!$check_access) { |
---|
785 | return REVISIONING_LOAD_LATEST; |
---|
786 | } |
---|
787 | $original_vid = $node->vid; |
---|
788 | $node->vid = $latest_vid; |
---|
789 | $node->is_current = node_tools_revision_is_current($node); |
---|
790 | $revision_op = ($op == 'view') ? 'view revisions' : 'edit revisions'; |
---|
791 | $access = _revisioning_node_revision_access($revision_op, $node); |
---|
792 | // Restore $node (even though called by value), so that it remains consistent |
---|
793 | $node->vid = $original_vid; |
---|
794 | $node->is_current = node_tools_revision_is_current($node); |
---|
795 | if ($access) { |
---|
796 | return REVISIONING_LOAD_LATEST; |
---|
797 | } |
---|
798 | } |
---|
799 | } |
---|
800 | } |
---|
801 | return REVISIONING_LOAD_CURRENT; |
---|
802 | } |
---|
803 | |
---|
804 | function _revisioning_prepare_msg($node) { |
---|
805 | if (!$node->nid) { // new node |
---|
806 | return; |
---|
807 | } |
---|
808 | $count = _revisioning_get_number_of_revisions_newer_than($node->vid, $node->nid); |
---|
809 | if ($count == 1) { |
---|
810 | drupal_set_message(t('Please note there is one revision more recent than the one you are about to edit.'), 'warning'); |
---|
811 | } |
---|
812 | elseif ($count > 1) { |
---|
813 | drupal_set_message(t('Please note there are !count revisions more recent than the one you are about to edit.', array('!count' => $count)), 'warning'); |
---|
814 | } |
---|
815 | } |
---|
816 | |
---|
817 | function _revisioning_insert_msg($node) { |
---|
818 | if ($node->status) { |
---|
819 | drupal_set_message(t('Initial revision created and published.')); |
---|
820 | } |
---|
821 | else { |
---|
822 | drupal_set_message(t('Initial draft created, pending publication.')); |
---|
823 | } |
---|
824 | } |
---|
825 | |
---|
826 | /** |
---|
827 | * Display all revisions of the supplied node in a themed table with links for |
---|
828 | * the permitted operations above it. |
---|
829 | */ |
---|
830 | function _revisioning_present_node($node, $op = 'any') { |
---|
831 | return ($op == 'edit' && !$node->revision_moderation) ? node_page_edit($node) :_theme_revisions_summary($node); |
---|
832 | } |
---|
833 | |
---|
834 | /** |
---|
835 | * Menu callback for the primary View tab. |
---|
836 | */ |
---|
837 | function _revisioning_view($node) { |
---|
838 | if (_revisioning_load_op($node, 'view') == REVISIONING_LOAD_LATEST) { |
---|
839 | $vid_to_load = revisioning_get_latest_revision_id($node->nid); |
---|
840 | $node = node_load($node->nid, $vid_to_load); |
---|
841 | } |
---|
842 | // In node.module, node_page_view() is used to display the current, while |
---|
843 | // node_show() is used for any other revision. The difference between the |
---|
844 | // two is that node_page_view() surpresses the message that tells us we're |
---|
845 | // viewing a revision. That's what we use here because we have our own |
---|
846 | // configurable message. |
---|
847 | return node_page_view($node); |
---|
848 | } |
---|
849 | |
---|
850 | /** |
---|
851 | * Callback for the primary Edit tab. |
---|
852 | */ |
---|
853 | function _revisioning_edit($node) { |
---|
854 | // Use the admin theme if the user specified this for node edit pages |
---|
855 | if (variable_get('node_admin_theme', FALSE)) { |
---|
856 | global $theme, $custom_theme; |
---|
857 | $custom_theme = variable_get('admin_theme', $theme); |
---|
858 | } |
---|
859 | if (_revisioning_load_op($node, 'edit') == REVISIONING_LOAD_LATEST) { |
---|
860 | $vid_to_load = revisioning_get_latest_revision_id($node->nid); |
---|
861 | $node = node_load($node->nid, $vid_to_load); |
---|
862 | } |
---|
863 | // Following is the same as node_page_edit(). |
---|
864 | drupal_set_title(check_plain($node->title)); |
---|
865 | return drupal_get_form($node->type .'_node_form', $node); |
---|
866 | } |
---|
867 | |
---|
868 | /** |
---|
869 | * Callback for the primary View and Edit tabs. |
---|
870 | * @param $node |
---|
871 | * @param $edit, bool |
---|
872 | * @return string |
---|
873 | */ |
---|
874 | function _revisioning_title_for_tab($node, $edit = FALSE) { |
---|
875 | if ($node->num_revisions <= 1 || !$node->revision_moderation) { |
---|
876 | return $edit ? t('Edit') : t('View'); |
---|
877 | } |
---|
878 | if (_revisioning_load_op($node, $edit ? 'edit' : 'view') == REVISIONING_LOAD_LATEST) { |
---|
879 | return $edit ? t('Edit latest') : t('View latest'); |
---|
880 | } |
---|
881 | return $edit ? t('Edit current') : t('View current'); |
---|
882 | } |
---|
883 | |
---|
884 | /** |
---|
885 | * Callback to view a particular revision. |
---|
886 | */ |
---|
887 | function _revisioning_view_revision($node) { |
---|
888 | if (isset($node->nid)) { |
---|
889 | $router_item = menu_get_item('node/' . $node->nid); |
---|
890 | if (!empty($router_item['file'])) { |
---|
891 | $path = $_SERVER['DOCUMENT_ROOT'] . base_path(); |
---|
892 | require_once $path . $router_item['file']; |
---|
893 | } |
---|
894 | // Call whatever function is assigned to the main node path but pass the |
---|
895 | // current node as an argument. This approach allows for the reuse of Panel |
---|
896 | // definition acting on node/%node. See [#1567880]. |
---|
897 | if (isset($router_item['page_callback'])) { |
---|
898 | return $router_item['page_callback']($node); |
---|
899 | } |
---|
900 | } |
---|
901 | return node_page_view($node); |
---|
902 | } |
---|
903 | |
---|
904 | /** |
---|
905 | * Callback to edit a particular revision. |
---|
906 | */ |
---|
907 | function _revisioning_edit_revision($node) { |
---|
908 | // Use the admin theme if the user specified this for node edit pages |
---|
909 | if (variable_get('node_admin_theme', FALSE)) { |
---|
910 | global $theme, $custom_theme; |
---|
911 | $custom_theme = variable_get('admin_theme', $theme); |
---|
912 | } |
---|
913 | drupal_set_title(check_plain($node->title)); |
---|
914 | return drupal_get_form($node->type .'_node_form', $node); |
---|
915 | } |
---|
916 | |
---|
917 | /** |
---|
918 | * Use diff's compare callback to compare specific revision to the current one |
---|
919 | */ |
---|
920 | if (module_exists('diff')) { |
---|
921 | function _revisioning_compare_to_current_revision($node) { |
---|
922 | module_load_include('inc', 'diff', 'diff.pages'); // for diff_diffs_show() |
---|
923 | // Make sure that latest of the two revisions is on the right |
---|
924 | if ($node->is_pending) { |
---|
925 | return diff_diffs_show($node, $node->current_revision_id, $node->vid); |
---|
926 | } |
---|
927 | return diff_diffs_show($node, $node->vid, $node->current_revision_id); |
---|
928 | } |
---|
929 | } |
---|