/[drupal]/contributions/modules/qedit/qedit.module
ViewVC logotype

Contents of /contributions/modules/qedit/qedit.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Tue Oct 7 18:15:05 2008 UTC (13 months, 3 weeks ago) by jimyhuang
Branch: MAIN
CVS Tags: DRUPAL-5--1-1, HEAD
Changes since 1.4: +198 -70 lines
File MIME type: text/x-php
Fix many bugs. Title update issue, date udate issue, mass delete issue...etc
1 <?php
2
3 /**
4 * Implementation of hook_menu()
5 */
6 function qedit_menu($may_cache){
7 $items = array();
8
9 if($may_cache){
10 $items[] = array(
11 'path' => 'admin/content/qedit',
12 'callback' => 'qedit_page',
13 'title' => t('Quick edit content'),
14 'access' => user_access('access qedit'),
15 'type' => MENU_NORMAL_ITEM,
16 );
17 }
18 else{
19 $items[] = array(
20 'path' => 'qedit/ajax-load',
21 'callback' => 'qedit_ajax',
22 'access' => user_access('access qedit'),
23 'type' => MENU_CALLBACK,
24 );
25 $items[] = array(
26 'path' => 'qedit/ajax-load/autoterm',
27 'callback' => 'qedit_autoterm',
28 'access' => user_access('access qedit'),
29 'type' => MENU_CALLBACK
30 );
31 $items[] = array(
32 'path' => 'qedit/ajax-load/autonode',
33 'callback' => 'qedit_autonode',
34 'access' => user_access('access qedit'),
35 'type' => MENU_CALLBACK
36 );
37 $items[] = array(
38 'path' => 'qedit/ajax-load/bodytip',
39 'callback' => 'qedit_bodytip',
40 'access' => user_access('access qedit'),
41 'type' => MENU_CALLBACK
42 );
43 $items[] = array(
44 'path' => 'qedit/ajax-save',
45 'callback' => 'qedit_ajax_save',
46 'access' => user_access('access qedit'),
47 'type' => MENU_CALLBACK
48 );
49 }
50 return $items;
51 }
52
53 /**
54 * Implementation of hook_perm()
55 */
56 function qedit_perm(){
57 // For further usage.
58 // return array('reaggrege post', 'admin qedit', 'access qedit');
59 }
60
61 /**
62 * Main page start for quick edit.
63 *
64 * This function will add filter interface and control interface for editor.
65 *
66 */
67 function qedit_page(){
68 // dirty hack for implement node delete.
69 if($_POST['op'] == t('Delete')) $_POST['operation'] = 'delete';
70 if ($_POST['operation'] == 'delete' && $_POST['nodes']) {
71 return drupal_get_form('qedit_multiple_delete_confirm');
72 }
73
74 $path = drupal_get_path('module', 'qedit');
75 drupal_add_css($path.'/qedit.css');
76 drupal_add_js($path.'/qedit.js');
77 drupal_add_js('misc/progress.js');
78 if(variable_get('clean_url', 1)) drupal_add_js('var clean_url = true;', 'inline');
79
80 $op = $_POST['op'];
81 $filter = $_SESSION['qedit_filter'];
82 $output .= '<div> &raquo; '.l(t('Create content'), "node/add").'</div><br>';
83 $output .= drupal_get_form('qedit_control_form', $filter);
84 $output .= drupal_get_form('qedit_table_form');
85 return $output;
86 }
87
88 /**
89 * Control form for filter content.
90 *
91 * @param $filter
92 * An array contain which user choose in last session. Callout by $_SESSION
93 *
94 * @ingroup forms
95 * @see qedit_control_form_submit()
96 */
97 function qedit_control_form($filter){
98 // global $dynasync;
99
100 $form = array();
101 $perm = user_access('administer nodes');
102 if($perm){
103 $form['qedit'] = array(
104 '#type' => 'fieldset',
105 '#title' => t('Filter buttons'),
106 '#collapsible' => TRUE,
107 '#collapsed' => FALSE,
108 '#tree' => TRUE,
109 );
110 $form['qedit']['range'] = array(
111 '#type' => 'fieldset',
112 '#title' => t('Range'),
113 '#prefix' => '<div class="container-inline">',
114 '#suffix' => '</div>',
115 '#tree' => TRUE,
116 );
117 $form['qedit']['range']['from'] = array(
118 '#type' => 'textfield',
119 '#title' => t('From date'),
120 '#default_value' => $filter['range']['from'] ? $filter['range']['from'] : '',
121 '#attributes' => array('class' => 'jscalendar'),
122 '#size' => '30',
123 );
124 $form['qedit']['range']['to'] = array(
125 '#type' => 'textfield',
126 '#title' => t('To date'),
127 '#default_value' => $filter['range']['to'] ? $filter['range']['to'] : '',
128 '#attributes' => array('class' => 'jscalendar'),
129 '#size' => '30',
130 );
131 $form['qedit']['tags'] = array(
132 '#type' => 'textfield',
133 '#title' => t('Category').' / '.t('Tag'),
134 '#default_value' => $filter['tags'] ? $filter['tags'] : '',
135 '#autocomplete_path' => 'qedit/ajax-load/autoterm',
136 '#weight' => 3,
137 '#maxlength' => 255,
138 '#prefix' => '<div class="container-inline">',
139 '#suffix' => '</div>',
140 );
141 $types = array_merge(array(0 => t('<all>')), node_get_types("names"));
142 $form['qedit']['type'] = array(
143 '#type' => 'select',
144 '#title' => t('Content type'),
145 '#default_value' => $filter['type'] ? $filter['type'] : '',
146 '#weight' => 3.5,
147 '#options' => $types,
148 '#prefix' => '<div class="container-inline">',
149 '#suffix' => '</div>',
150 );
151 $form['qedit']['title'] = array(
152 '#type' => 'textfield',
153 '#title' => t('Title'),
154 '#default_value' => $filter['title'] ? $filter['title'] : '',
155 '#autocomplete_path' => 'qedit/ajax-load/autonode',
156 '#weight' => 4,
157 '#maxlength' => 255,
158 '#prefix' => '<div class="container-inline">',
159 '#suffix' => '</div>',
160 );
161 $form['qedit']['status'] = array(
162 '#type' => 'select',
163 '#title' => t('Status'),
164 '#default_value' => $filter['status'] ? $filter['status'] : 0,
165 '#options' => array(0 => t('<all>'), 1 => t('not published'), 2 => t('published')),
166 '#prefix' => '<div class="container-inline">',
167 '#suffix' => '</div>',
168 '#weight' => 10,
169 );
170 $form['qedit']['op'] = array(
171 '#type' => 'submit',
172 '#value' => t('Filter'),
173 '#id' => 'filter-button',
174 '#weight' => 20,
175 );
176 if(isset($_SESSION['qedit_filter'])){
177 $form['qedit']['reset'] = array(
178 '#type' => 'submit',
179 '#value' => t('Reset filter'),
180 '#id' => 'reset-button',
181 '#weight' => 21,
182 );
183 }
184 return $form;
185 }
186 }
187
188 /**
189 * Remember user choosed filter when they submit.
190 */
191 function qedit_control_form_submit($form_id, $form_values) {
192 if($form_values['op'] == t('Filter')){
193 if(isset($_SESSION['qedit_filter'])){
194 unset($_SESSION['qedit_filter']);
195 }
196 $_SESSION['qedit_filter'] = $form_values['qedit'];
197 }
198 elseif($form_values['op'] == t('Reset filter')){
199 unset($_SESSION['qedit_filter']);
200 }
201 }
202
203 /**
204 * Main title list table that user submit their filter.
205 *
206 * @ingroup forms
207 * @see theme_qedit_table_form()
208 */
209 function qedit_table_form(){
210 $filter = qedit_filter_query($_SESSION['qedit_filter']);
211
212 $form = array();
213 $destination = drupal_get_destination();
214 $sql = "SELECT * FROM {node} n ".$filter['join']." ".$filter['where']." ORDER BY n.created DESC";
215 $string = drupal_query_string_encode($_REQUEST, array_merge(array('q', 'page'), array_keys($_COOKIE)));
216 $result = pager_query(db_rewrite_sql($sql), 20, 0, NULL, $filter['args']);
217 while($n = db_fetch_object($result)){
218 // collect row data and generate form
219 $nodes[$n->nid] = '';
220 $form['title'][$n->nid] = array('#value' => check_plain($n->title), '#prefix' => '<div class="title" id="title-'.$n->nid.'">', '#suffix' => '</div>', );
221 $form['created'][$n->nid] = array('#value' => format_date($n->created, 'custom', 'Y-m-d H:i:s'), '#prefix' => '<div class="date" id="date-'.$n->nid.'">', '#suffix' => '</div>',);
222
223 $form['status'][$n->nid] = array('#value' => ($n->status ? t('published') : t('not published')));
224 $form['operations'][$n->nid] = array('#value' => l(t('edit'), 'node/'. $n->nid .'/edit', NULL, $destination));
225 }
226 $form['message'] = array('#value' => ' ', '#prefix' => '<div id="message">', '#suffix' => '</div>');
227
228 $form['nodes'] = array('#type' => 'checkboxes', '#options' => $nodes);
229 $operations = array(
230 0 => t('<none>'),
231 1 => t('Publish'),
232 );
233 $form['tag'] = array('#type' => 'fieldset',
234 '#title' => t('Batch add tag or category'),
235 '#tree' => TRUE,
236 '#prefix' => '<div class="container-inline">',
237 '#suffix' => '</div>',
238 );
239 $form['tag']['tags'] = array('#type' => 'textfield', '#default_value' => '','#autocomplete_path' => 'qedit/ajax-load/autoterm', '#maxlength' => 255,);
240 $form['tag']['save'] = array('#type' => 'button', '#value' => t('Save'), '#attributes' => array('class' => 'ajax-button'),);
241 $form['options'] = array('#type' => 'fieldset',
242 '#title' => t('Operations'),
243 '#tree' => TRUE,
244 '#prefix' => '<div class="container-inline">',
245 '#suffix' => '</div>',
246 );
247 foreach (module_invoke_all('node_operations') as $operation => $array) {
248 if($operation == 'delete') continue;
249 $options[$operation] = $array['label'];
250 }
251 $form['options']['operation'] = array('#type' => 'select', '#options' => $options, '#default_value' => 'approve');
252 $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Update'), '#attributes' => array('class' => 'ajax-button'),);
253
254 // Because delete need confirm process, we can't use AJAX to delete nodes.
255 $form['options']['or'] = array('#value' => t('Or'));
256 $form['options']['delete'] = array('#type' => 'submit', '#value' => t('Delete'), '#attributes' => array('class'=> 'delete'),);
257
258 $form['type'] = array('#type' => 'hidden', '#value' => 'batch');
259 $form['ajax-url'] = array('#type' => 'hidden', '#value' => url('qedit/ajax-save', NULL, NULL, TRUE), '#attributes' => array('class' => 'ajax-save-url'));
260 $form['ajax-load-url'] = array('#type' => 'hidden', '#value' => url('qedit/ajax-load/bodytip', NULL, NULL, TRUE), '#attributes' => array('class' => 'ajax-load-url'));
261 $form['ajax-form-token'] = array('#type' => 'hidden', '#value' => drupal_get_token('qedit_table_form'), '#attributes' => array('class' => 'ajax-form-token'));
262
263 $form['pager'] = array('#value' => theme('pager', NULL, 20, 0));
264
265 return $form;
266 }
267
268 /**
269 * Theme function for qedit_table_form()
270 */
271 function theme_qedit_table_form($form){
272 $header = array('#', theme('table_select_header_cell'), t('Title'), t('Created Time'), t('Status'), t('Operations'));
273
274 if (isset($form['title']) && is_array($form['title'])) {
275 foreach (element_children($form['title']) as $key) {
276 $row = array();
277 $row[] = ++$count_row;
278 $row[] = drupal_render($form['nodes'][$key]);
279 $row[] = drupal_render($form['title'][$key]);
280 $row[] = drupal_render($form['created'][$key]);
281 $row[] = drupal_render($form['status'][$key]);
282 $row[] = drupal_render($form['operations'][$key]);
283 $rows[] = $row;
284 }
285 }
286 else {
287 $rows[] = array(array('data' => t('No posts available.'), 'colspan' => '5'));
288 }
289
290 $output .= theme('table', $header, $rows);
291 if ($form['pager']['#value']) {
292 $pager = drupal_render($form['pager']);
293 $output = $pager . $output . $pager;
294 }
295 $output .= drupal_render($form['message']);
296 $output .= drupal_render($form);
297
298 return $output;
299 }
300
301 /**
302 * Helper function for return query.
303 *
304 * @param $be
305 * An array that $_SESSION['qedit_filter'] stored.
306 *
307 * @return
308 * An array contain where/join/args query string.
309 */
310 function qedit_filter_query($be) {
311 $where = $args = array();
312 $join = '';
313 if(is_array($be)){
314 foreach ($be as $type => $value) {
315 switch($type){
316 case 'title':
317 if(empty($value)) break;
318 $title = trim(check_plain($value));
319 $where[] = "n.title LIKE '%%%s%%'";
320 $args[$type] = $value;
321 break;
322 case 'tags':
323 if(empty($value)) break;
324 $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
325 preg_match_all($regexp, $value, $matches);
326 if(is_array($matches[1])){
327 $require_terms = array_unique($matches[1]);
328 }
329 foreach($require_terms as $name){
330 if($tid = db_result(db_query("SELECT tid FROM {term_data} WHERE name = '%s'", $name))){
331 $tids[] = $tid;
332 }
333 }
334 $where[] = "tn.tid IN(".implode(',',$tids).")";
335 $join .= "INNER JOIN {term_node} tn ON n.nid = tn.nid ";
336 break;
337 case 'range':
338 $range = $value;
339 $timestamp = 0;
340 if($timestamp = strtotime($range['from'])){
341 $where[] = "n.created >= %d";
342 $args['from'] = $timestamp;
343 }
344 $timestamp = 0;
345 if($timestamp = strtotime($range['to'])){
346 $where[] = "n.created <= %d";
347 $args['to'] = $timestamp;
348 }
349 break;
350 case 'status':
351 if(empty($value)) break;
352 $status = $value - 1;
353 $where[] = "n.status = %d";
354 $args[$type] = $status;
355 break;
356 case 'type':
357 if(empty($value)) break;
358 $type = $value;
359 $where[] = "n.type = '%s'";
360 $args[$type] = $type;
361 break;
362 }
363 }
364 }
365 $where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';
366
367 return array('where' => $where, 'join' => $join, 'args' => $args);
368 }
369
370 /**
371 * Ajax autocomcplete help function for get term name.
372 *
373 * @param $string
374 * An empty string for sending search keyword.
375 */
376 function qedit_autoterm($string = '') {
377 // The user enters a comma-separated list of tags. We only autocomplete the last tag.
378 // This regexp allows the following types of user input:
379 // this, "somecmpany, llc", "and ""this"" w,o.rks", foo bar
380 $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
381 preg_match_all($regexp, $string, $matches);
382 $array = $matches[1];
383
384 // Fetch last tag
385 $last_string = trim(array_pop($array));
386 if ($last_string != '') {
387 $result = db_query_range("SELECT t.tid, t.name FROM {term_data} t WHERE LOWER(t.name) LIKE LOWER('%%%s%%')", $last_string, 0, 25);
388
389 $prefix = count($array) ? implode(', ', $array) .', ' : '';
390
391 $matches = array();
392 while ($tag = db_fetch_object($result)) {
393 $n = $tag->name;
394 // Commas and quotes in terms are special cases, so encode 'em.
395 if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
396 $n = '"'. str_replace('"', '""', $tag->name) .'"';
397 }
398 $matches[$prefix . $n] = check_plain($tag->name);
399 }
400 print drupal_to_js($matches);
401 exit();
402 }
403 }
404
405 /**
406 * Ajax autocomplete for get node title.
407 *
408 * @param $string
409 * An empty string for sending search keyword.
410 */
411 function qedit_autonode($string = '') {
412 $result = db_query("SELECT n.nid, n.title FROM {node} n WHERE n.title LIKE '%%%s%' ORDER BY n.title", $string);
413 $matches = array();
414 while ($n = db_fetch_object($result)) {
415 $matches["$n->title"] = check_plain($n->title);
416 }
417
418 print drupal_to_js($matches);
419 exit();
420 }
421
422 /**
423 * Function for handling all ajax save.
424 */
425 function qedit_ajax_save(){
426 // valid token for security concern.
427 if(!drupal_valid_token($_POST['form_token'], 'qedit_table_form')){
428 exit();
429 }
430 $type = $_POST['type'];
431 switch($type){
432 case 'title':
433 if(is_numeric($_POST['nid'])){
434 $nid = $_POST['nid'];
435 $updated_node = node_load($nid);
436 $title = check_plain($_POST['content']);
437 if($updated_node->title != $title && $updated_node->nid){
438 $updated_node->title = $title;
439 // can't update title directly. Need use node_save
440 node_save($updated_node);
441 }
442 else{
443 drupal_set_message(t('Same title, didn\'t save.'), 'error');
444 }
445 }
446 else{
447 drupal_set_message('Don\'t treating us.', 'error');
448 }
449 break;
450
451 case 'date':
452 $nid = $_POST['nid'];
453 if(($date = strtotime($_POST['content'])) && is_numeric($nid) ){
454 db_query("UPDATE {node} SET created = %d WHERE nid = %d", $date, $nid);
455 }
456 else{
457 drupal_set_message(t('Please correct your datetime format.'), 'error');
458 }
459 break;
460
461 case 'batch':
462 $nodes = $_POST['nodes'];
463 if(empty($nodes)){
464 drupal_set_message('You must selet at least one content to update.', 'error');
465 break;
466 }
467 $op = $_POST['op'];
468 if($op == t('Save')){
469 if(!empty($_POST['tag']['tags'])){
470 $tags = $_POST['tag']['tags'];
471 $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
472 preg_match_all($regexp, $tags, $matches);
473 if(is_array($matches[1])){
474 $tag = $matches[1][0];
475 }
476 $tag = trim($tag);
477 $ptag = taxonomy_get_term_by_name($tag);
478 $tid = $ptag[0]->tid;
479 if($tid){
480 foreach($nodes as $nid){
481 db_query("DELETE FROM {term_node} WHERE tid = %d AND nid = %d", $tid, $nid);
482 db_query("INSERT INTO {term_node} (tid,nid) VALUES (%d,%d)", $tid, $nid);
483 }
484 drupal_set_message(t("Update successfuly"));
485 }
486 else{
487 drupal_set_message(t('You can only save exist tag/category. This is not an avaiable tag/category.'), 'error');
488 }
489 }
490 }
491
492 if($op == t('Update')){
493 $form_values = array('nodes' => $_POST['nodes'], 'operation' => $_POST['options']['operation']);
494 node_admin_nodes_submit($_POST['form_id'], $form_values);
495 }
496
497 break;
498 }
499 $output .= theme('status_messages');
500 print drupal_to_js(array('status' => TRUE, 'data'=> $output));
501 exit();
502 }
503
504 function qedit_multiple_delete_confirm() {
505 $edit['nodes'] = $_POST['nodes'];
506 $edit['operation'] = 'delete';
507
508 $form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
509 // array_filter returns only elements with TRUE values
510 foreach (array_filter($edit['nodes']) as $nid => $value) {
511 $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
512 $form['nodes'][$nid] = array('#type' => 'hidden', '#value' => $nid, '#prefix' => '<li>', '#suffix' => check_plain($title) ."</li>\n");
513 }
514 $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
515
516 return confirm_form($form,
517 t('Are you sure you want to delete these items?'),
518 'admin/content/qedit', t('This action cannot be undone.'),
519 t('Delete all'), t('Cancel'));
520 }
521
522 function qedit_multiple_delete_confirm_submit($form_id, $form_values) {
523 if ($form_values['confirm']) {
524 foreach ($form_values['nodes'] as $nid => $value) {
525 node_delete($nid);
526 }
527 drupal_set_message(t('The items have been deleted.'));
528 }
529 return 'admin/content/qedit';
530 }
531
532 /**
533 * Debug function
534 */
535 function dbr($in){
536 ob_start();
537 print '<pre>';
538 print_r($in);
539 print '</pre>';
540 $output .= ob_get_contents();
541 ob_end_clean();
542 return $output;
543 }
544
545 function qedit_bodytip(){
546 $nid = $_GET['nid'];
547 $n = node_load($nid);
548 if($n->type == 'image'){
549 $sizes = image_get_sizes();
550 foreach($sizes as $label => $info){
551 if($label == '_original') continue;
552 $output .= '<div>'. image_display($n, $label) .'</div>';
553 }
554 }
555 else{
556 $output = node_view($n, FALSE, FALSE, FALSE);
557 }
558 print $output;
559 }
560

  ViewVC Help
Powered by ViewVC 1.1.2