← All changes
|
includes/admin/tasks/open_task/wppm_open_task.php
+480
-45
5.0.7
→
6.0.6
View file →
| @@ -30,9 +30,12 @@ | ||
| 30 | 30 | if ( $auth_code && $auth_id == $auth_code ) { |
| 31 | 31 | $url_auth = true; |
| 32 | 32 | } |
| 33 | 33 | if (!(($current_user->ID && $current_user->has_cap('manage_options')) || ($wppmfunction->has_permission('view_task',$id)) || ($url_auth==true))) { ?> |
| 34 | - <div style="align-item:center;" ><h6><?php esc_attr_e( 'Unauthorized access!', 'taskbuilder' ); ?></h6></div> | |
| 34 | + <div style="text-align:center;padding:20px 0;"> | |
| 35 | + <h6><?php esc_attr_e( 'Unauthorized access!', 'taskbuilder' ); ?></h6> | |
| 36 | + <a href="<?php echo esc_url( admin_url('admin.php?page=wppm-tasks') ); ?>" class="btn btn-success btn-sm"><?php esc_html_e( 'Go to Task List', 'taskbuilder' ); ?></a> | |
| 37 | + </div> | |
| 35 | 38 | <?php |
| 36 | 39 | wp_die(); |
| 37 | 40 | } |
| 38 | 41 | $proj_id = isset($_POST) && isset($_POST['proj_id']) ? intval(sanitize_text_field(wp_unslash($_POST['proj_id']))) : 0; |
| @@ -229,9 +232,9 @@ | ||
| 229 | 232 | <span class="wppm-dashboard-btn" id="wppm_dashboard_btn" title="<?php esc_attr_e( 'Dashboard', 'taskbuilder' ); ?>" onclick="wppm_get_project_tasks(<?php echo esc_attr($proj_id) ?>)"> |
| 230 | 233 | <a href="<?php echo esc_url(admin_url('admin.php?page=wppm-dashboard')); ?>"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/dashboard-icon.svg'); ?>" alt="dashboard"></a> |
| 231 | 234 | </span> |
| 232 | 235 | <span class="wppm-delete_task_btn" id="wppm_delete_task_btn" title="Delete Task" onclick="wppm_get_delete_task(<?php echo esc_attr($id) ?>,<?php echo esc_attr($proj_id) ?>,<?php echo esc_attr($project_id) ?>)" style="<?php echo esc_attr($style) ?>"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/bin.svg'); ?>" alt="delete"></span> |
| 233 | - <div class="wppm-clone_task_btn" id="wppm_clone_task_btn" title="Clone Task" onclick="wppm_clone_task(<?php echo esc_attr($id) ?>,<?php echo esc_attr($proj_id)?>,<?php echo esc_attr($project_id) ?>)" style="<?php echo esc_attr($clone_style) ?>"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/duplicate.svg'); ?>" alt="clone"></div> | |
| 236 | + <span class="wppm-clone_task_btn" id="wppm_clone_task_btn" title="Clone Task" onclick="wppm_clone_task(<?php echo esc_attr($id) ?>,<?php echo esc_attr($proj_id)?>,<?php echo esc_attr($project_id) ?>)" style="<?php echo esc_attr($clone_style) ?>"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/duplicate.svg'); ?>" alt="clone"></span> | |
| 234 | 237 | <span class="wppm-print_task_btn" id="wppm_print_task_btn" title="Print Task" onclick="wppm_print_task(<?php echo esc_attr($id) ?>)"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/printer_menu.svg'); ?>" alt="print" style="<?php echo esc_attr($ar_css);?>"></span> |
| 235 | 238 | <span class="wppm-archieve_task_btn" id="wppm_archieve_task_btn" title="<?php echo ($task->is_archived==1 ) ? 'Restore Task' : 'Archive Task'; ?>" onclick="wppm_archive_task(<?php echo esc_attr($id) ?>,<?php echo esc_attr($task->is_archived) ?>,<?php echo esc_attr($project_id) ?>)" style="<?php echo esc_attr($archive_style) ?>"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/archive.svg'); ?>" alt="archive"></span> |
| 236 | 239 | <input type="hidden" name="wppm_archive_task_ajax_nonce" id="wppm_archive_task_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_archive_task_ajax_nonce' ) ); ?>"> |
| 237 | 240 | <div class="menu" id="wppmprint_menu" onclick="event.stopPropagation();"> |
| @@ -238,9 +241,9 @@ | ||
| 238 | 241 | <a href="#" id="wppm_openPDF" onclick="wppm_open_pdf(<?php echo esc_attr($id) ?>)">🖨️ <?php echo esc_html_e('Open In Browser','taskbuilder');?></a> |
| 239 | 242 | <a href="#" id="wppm_downloadPDF" onclick="wppm_download_pdf(<?php echo esc_attr($id) ?>)">💾 <?php echo esc_html_e('Download PDF','taskbuilder');?></a> |
| 240 | 243 | </div> |
| 241 | 244 | <?php do_action('wppm_individual_task_button',$id);?> |
| 242 | - </div> | |
| 245 | + </div> | |
| 243 | 246 | </div> |
| 244 | 247 | <div id="wppm_load_individual_task_container" class="row"> |
| 245 | 248 | <div class="col-sm-8 wppm_body col-md-9"> |
| 246 | 249 | <div class="wppm_task_details_container"> |
| @@ -250,8 +253,23 @@ | ||
| 250 | 253 | <?php if (($wppmfunction->has_permission('change_task_details',$id) || $current_user->has_cap('manage_options') || $wppm_current_user_capability == 'wppm_admin') && $task->is_archived!=1) { ?> |
| 251 | 254 | <span id="wppm_individual_edit_task_subject" onclick="wppm_edit_task_details(<?php echo esc_attr($id) ?>,<?php echo esc_attr($proj_id) ?>,<?php echo esc_attr($project_id) ?>)" class="btn btn-sm wppm_action_btn" style="background-color:#FFFFFF !important;color:#000000 !important;"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/edit_01.svg'); ?>" alt="edit"></span> |
| 252 | 255 | <?php } ?> |
| 253 | 256 | </span> |
| 257 | + <?php if(!empty($task->parent_task_id)){ | |
| 258 | + $wppm_parent_task = $wpdb->get_row( $wpdb->prepare("SELECT id, task_name FROM {$wpdb->prefix}wppm_task where id=%d",absint($task->parent_task_id))); | |
| 259 | + if(!empty($wppm_parent_task)){ | |
| 260 | + $wppm_can_convert_subtask = (($current_user->has_cap('manage_options') || $wppmfunction->has_permission('delete_task',$id)) && $task->is_archived!=1); | |
| 261 | + ?> | |
| 262 | + <div class="wppm_subtask_parent_link"> | |
| 263 | + <?php echo esc_html_e('Subtask of','taskbuilder');?> | |
| 264 | + <a href="#" onclick="wppm_open_subtask(<?php echo esc_attr($wppm_parent_task->id) ?>,<?php echo esc_attr($proj_id) ?>);return false;"><?php echo esc_html($wppm_parent_task->task_name); ?></a> | |
| 265 | + <?php if($wppm_can_convert_subtask){ ?> | |
| 266 | + | <a href="#" onclick="wppm_convert_subtask_to_task(<?php echo esc_attr($id) ?>,<?php echo esc_attr($id) ?>,<?php echo esc_attr($proj_id) ?>);return false;"><?php echo esc_html_e('Convert to Task','taskbuilder');?></a> | |
| 267 | + <input type="hidden" name="wppm_convert_subtask_to_task_ajax_nonce" id="wppm_convert_subtask_to_task_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_convert_subtask_to_task' ) ); ?>"> | |
| 268 | + <?php } ?> | |
| 269 | + </div> | |
| 270 | + <?php } | |
| 271 | + } ?> | |
| 254 | 272 | </div> |
| 255 | 273 | </div> |
| 256 | 274 | <div class="row"> |
| 257 | 275 | <div class="col-sm-3"> |
| @@ -342,8 +360,168 @@ | ||
| 342 | 360 | </div> |
| 343 | 361 | </div> |
| 344 | 362 | <?php do_action('wppm_after_task_details_in_open_task',$task->id, $task->project);?> |
| 345 | 363 | </div> |
| 364 | + <?php if(empty($task->parent_task_id)){ | |
| 365 | + $wppm_subtasks = $wppmfunction->get_subtasks($task_id); | |
| 366 | + $wppm_subtask_progress = $wppmfunction->get_subtask_progress($task_id); | |
| 367 | + $wppm_default_task_status = get_option('wppm_default_task_status'); | |
| 368 | + $wppm_can_add_subtask = (($current_user->has_cap('manage_options') || $wppmfunction->has_permission('add_new_task',$task_id)) && $task->is_archived!=1 && $user_role != 3); | |
| 369 | + ?> | |
| 370 | + <div class="wppm_task_subtask_container" id="wppm_task_subtask_container"> | |
| 371 | + <div class="row"> | |
| 372 | + <div class="col-sm-8"> | |
| 373 | + <span class="wppm_checklist_label"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/task_list.svg'); ?>" alt="subtasks"><?php echo esc_html_e('Subtasks','taskbuilder');?></span> | |
| 374 | + </div> | |
| 375 | + </div> | |
| 376 | + <?php if($wppm_subtask_progress['total'] > 0){ | |
| 377 | + $wppm_subtask_percent = round(($wppm_subtask_progress['completed'] / $wppm_subtask_progress['total']) * 100); ?> | |
| 378 | + <div class="wppm_progress_bar_container row"> | |
| 379 | + <div class="col-sm-4"> | |
| 380 | + <span class="wppm_progressbar_label" id="wppm_subtask_progress_label"><?php echo esc_html($wppm_subtask_progress['completed'].'/'.$wppm_subtask_progress['total']); ?></span> | |
| 381 | + </div> | |
| 382 | + <div class="wppm_progress_bar col-sm-8"> | |
| 383 | + <div id="wppm_subtask_progressbar" class="wppm_checkprogress" role="progressbar" style="width: <?php echo esc_attr($wppm_subtask_percent); ?>%;background:#5ba4cf;" aria-valuemin="0" aria-valuemax="100"></div> | |
| 384 | + </div> | |
| 385 | + </div> | |
| 386 | + <?php } ?> | |
| 387 | + <input type="hidden" name="wppm_set_change_task_status_ajax_nonce" id="wppm_subtask_status_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_set_change_task_status' ) ); ?>"> | |
| 388 | + <input type="hidden" name="wppm_add_new_subtask_ajax_nonce" id="wppm_add_new_subtask_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_add_new_subtask' ) ); ?>"> | |
| 389 | + <input type="hidden" name="wppm_remove_subtask_ajax_nonce" id="wppm_remove_subtask_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_remove_subtask' ) ); ?>"> | |
| 390 | + <input type="hidden" name="wppm_convert_subtask_to_task_ajax_nonce" id="wppm_convert_subtask_to_task_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wppm_convert_subtask_to_task' ) ); ?>"> | |
| 391 | + <ul id="wppm_subtask_items_container" class="wppm_checklist_items_container" style="list-style-type: none; padding-left:0px; margin-top:10px; margin-bottom:10px;"> | |
| 392 | + <?php if(!empty($wppm_subtasks)){ | |
| 393 | + foreach($wppm_subtasks as $subtask){ | |
| 394 | + $wppm_subtask_checked = ($subtask['status']==4) ? 'checked="checked"' : ''; | |
| 395 | + $wppm_subtask_users = !empty($subtask['users']) ? explode(",",$subtask['users']) : array(); | |
| 396 | + $wppm_subtask_can_change_status = ($current_user->has_cap('manage_options') || $wppmfunction->has_permission('change_status',$subtask['id'])) && $task->is_archived!=1; | |
| 397 | + $wppm_subtask_can_delete = ($current_user->has_cap('manage_options') || $wppmfunction->has_permission('delete_task',$subtask['id'])) && $task->is_archived!=1; | |
| 398 | + ?> | |
| 399 | + <li id="wppm_subtask_<?php echo esc_attr($subtask['id']) ?>" class="row wppm_checklist_item" style="margin-bottom:10px;font: 15px 'Helvetica Neue',Helvetica,Arial,sans-serif;"> | |
| 400 | + <div class="col-sm-8"> | |
| 401 | + <input id="wppm_subtask_checkbox_<?php echo esc_attr($subtask['id']) ?>" type="checkbox" onchange="wppm_toggle_subtask_status(<?php echo esc_attr($subtask['id']) ?>,<?php echo esc_attr($task_id) ?>,<?php echo esc_attr($proj_id) ?>,<?php echo esc_attr($wppm_default_task_status) ?>,this.checked)" <?php echo esc_attr($wppm_subtask_checked) ?> <?php echo $wppm_subtask_can_change_status ? '' : 'disabled'; ?> style="margin:5px;"> | |
| 402 | + <label style="padding-top: 5px;font-weight: normal;font: 13px 'Helvetica Neue',Helvetica,Arial,sans-serif;cursor:pointer;" onclick="wppm_open_subtask(<?php echo esc_attr($subtask['id']) ?>,<?php echo esc_attr($proj_id) ?>)"><?php echo esc_html($subtask['task_name']); ?></label> | |
| 403 | + </div> | |
| 404 | + <div class="col-sm-4" style="text-align:right;"> | |
| 405 | + <?php $wppm_subtask_avatar_count = 0; | |
| 406 | + $wppm_subtask_total_users = count( array_filter( $wppm_subtask_users ) ); | |
| 407 | + foreach($wppm_subtask_users as $wppm_subtask_user_id){ | |
| 408 | + if(!$wppm_subtask_user_id) continue; | |
| 409 | + $wppm_subtask_avatar_count++; | |
| 410 | + if($wppm_subtask_avatar_count > 3) break; | |
| 411 | + $wppm_subtask_user_data = get_userdata($wppm_subtask_user_id); | |
| 412 | + $wppm_subtask_user_name = !empty($wppm_subtask_user_data) ? $wppm_subtask_user_data->display_name : ''; | |
| 413 | + echo get_avatar($wppm_subtask_user_id, 20, "mysteryman", $wppm_subtask_user_name, array('extra_attr' => 'title="'.esc_attr($wppm_subtask_user_name).'"')); | |
| 414 | + } | |
| 415 | + $wppm_subtask_more_users = $wppm_subtask_total_users - 3; | |
| 416 | + if ( $wppm_subtask_more_users > 0 ) { | |
| 417 | + ?> | |
| 418 | + <span class="wppm_subtask_more_users" title="<?php echo esc_attr( sprintf( _n( '%d more user assigned', '%d more users assigned', $wppm_subtask_more_users, 'taskbuilder' ), $wppm_subtask_more_users ) ); ?>">+<?php echo esc_html( $wppm_subtask_more_users ); ?></span> | |
| 419 | + <?php | |
| 420 | + } ?> | |
| 421 | + <?php if($wppm_subtask_can_delete){ ?> | |
| 422 | + <a href="#" title="<?php echo esc_attr__('Convert to Task','taskbuilder'); ?>" onclick="wppm_convert_subtask_to_task(<?php echo esc_attr($subtask['id']) ?>,<?php echo esc_attr($task_id) ?>,<?php echo esc_attr($proj_id) ?>);return false;" style="font-size:11px;margin-right:8px;"><?php echo esc_html_e('Convert to Task','taskbuilder');?></a> | |
| 423 | + <span onclick="wppm_delete_subtask(<?php echo esc_attr($subtask['id']) ?>,<?php echo esc_attr($task_id) ?>,<?php echo esc_attr($proj_id) ?>)" style="cursor:pointer;"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/trash.svg'); ?>" alt="delete"></span> | |
| 424 | + <?php } ?> | |
| 425 | + </div> | |
| 426 | + </li> | |
| 427 | + <?php | |
| 428 | + } | |
| 429 | + } ?> | |
| 430 | + </ul> | |
| 431 | + <?php if($wppm_can_add_subtask){ | |
| 432 | + $wppm_all_task_statuses = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wppm_task_statuses ORDER BY load_order ASC"); | |
| 433 | + ?> | |
| 434 | + <div class="row"> | |
| 435 | + <div class="col-sm-12" style="padding-top:15px;"> | |
| 436 | + <a class="wppm_add_checklist" id="wppm_add_subtask_btn" onclick="wppm_show_add_subtask()"><?php echo esc_html_e('+ Add subtask','taskbuilder');?></a> | |
| 437 | + </div> | |
| 438 | + </div> | |
| 439 | + <div class="row"> | |
| 440 | + <div class="col-sm-12" style="display:none;" id="wppm_add_subtask_label_container"> | |
| 441 | + <div class="row"> | |
| 442 | + <div class="wppm_task_frm_fields col-sm-6"> | |
| 443 | + <span class="wppm_form_field_label"><b><?php echo esc_html_e('Subtask Name','taskbuilder');?></b> <span style="color:#ff0000;">*</span></span><br> | |
| 444 | + <input type="text" id="wppm_subtask_label" class="form-control" placeholder="<?php echo esc_attr__('Subtask name','taskbuilder') ?>" name="wppm_subtask_label"> | |
| 445 | + </div> | |
| 446 | + <div class="wppm_task_frm_fields col-sm-6"> | |
| 447 | + <span class="wppm_form_field_label"><b><?php echo esc_html_e('Status','taskbuilder');?></b></span><br> | |
| 448 | + <select id="wppm_subtask_status" name="wppm_subtask_status" class="form-control"> | |
| 449 | + <?php if(!empty($wppm_all_task_statuses)){ | |
| 450 | + foreach($wppm_all_task_statuses as $wppm_st){ ?> | |
| 451 | + <option value="<?php echo esc_attr($wppm_st->id) ?>" <?php selected($wppm_st->id, $wppm_default_task_status); ?>><?php echo esc_html($wppm_st->name) ?></option> | |
| 452 | + <?php } | |
| 453 | + } ?> | |
| 454 | + </select> | |
| 455 | + </div> | |
| 456 | + </div> | |
| 457 | + <div class="row"> | |
| 458 | + <div class="wppm_task_frm_fields col-sm-6"> | |
| 459 | + <span class="wppm_form_field_label"><b><?php echo esc_html_e('Due date','taskbuilder');?></b></span><br> | |
| 460 | + <input type="text" id="wppm_subtask_due_date" class="form-control" name="wppm_subtask_due_date" value="" autocomplete="off"> | |
| 461 | + </div> | |
| 462 | + <div class="wppm_task_frm_fields col-sm-6"> | |
| 463 | + <span class="wppm_form_field_label"><b><?php echo esc_html_e('Assignee','taskbuilder');?></b></span><br> | |
| 464 | + <input class="form-control wppm_subtask_assign_users ui-autocomplete-input" name="wppm_subtask_assign_users" type="text" autocomplete="off" placeholder="<?php echo esc_attr__('Search User...','taskbuilder');?>"> | |
| 465 | + </div> | |
| 466 | + </div> | |
| 467 | + <div class="row"> | |
| 468 | + <div class="col-sm-12"> | |
| 469 | + <ul class="wppm_subtask_filter_display_users_container" style="list-style:none;padding-left:0;"></ul> | |
| 470 | + </div> | |
| 471 | + </div> | |
| 472 | + <div class="row"> | |
| 473 | + <div class="wppm_task_frm_fields col-sm-12"> | |
| 474 | + <span class="wppm_form_field_label"><b><?php echo esc_html_e('Description','taskbuilder');?></b></span><br> | |
| 475 | + <textarea id="wppm_subtask_description" name="wppm_subtask_description" class="form-control" rows="3"></textarea> | |
| 476 | + </div> | |
| 477 | + </div> | |
| 478 | + <div class="row" style="padding-top:10px;"> | |
| 479 | + <div class="col-sm-12"> | |
| 480 | + <input type="button" value="<?php echo esc_attr__('Add','taskbuilder') ?>" class="btn btn-success btn-sm" onclick="wppm_add_new_subtask(<?php echo esc_attr($task_id)?>,<?php echo esc_attr($proj_id) ?>)"> | |
| 481 | + <button type="button" class="wppm_reset_btn" onclick="wppm_hide_add_subtask()"><?php echo esc_html_e('Cancel','taskbuilder');?></button> | |
| 482 | + </div> | |
| 483 | + </div> | |
| 484 | + </div> | |
| 485 | + </div> | |
| 486 | + <script type="text/javascript"> | |
| 487 | + jQuery(document).ready(function(){ | |
| 488 | + jQuery('#wppm_subtask_due_date').flatpickr({ | |
| 489 | + enableTime: true, | |
| 490 | + dateFormat: "Y-m-d H:i" | |
| 491 | + }); | |
| 492 | + jQuery('.wppm_subtask_assign_users').autocomplete({ | |
| 493 | + minLength: 1, | |
| 494 | + appendTo: jQuery('.wppm_subtask_assign_users').parent(), | |
| 495 | + source: function(request, response){ | |
| 496 | + jQuery.getJSON(wppm_admin.ajax_url, { | |
| 497 | + action: 'wppm_filter_autocomplete', | |
| 498 | + term: request.term, | |
| 499 | + field: 'task_users_by_project_name', | |
| 500 | + proj_id: <?php echo (int) $task->project; ?> | |
| 501 | + }, function(data){ response(data); }); | |
| 502 | + }, | |
| 503 | + select: function(event, ui){ | |
| 504 | + if(!ui.item.user_id){ return false; } | |
| 505 | + var html_str = '<li class="wppm_filter_display_element" style="list-style:none">' | |
| 506 | + +'<div class="flex-container">' | |
| 507 | + +'<div class="wppm_filter_display_text">' | |
| 508 | + + ui.item.label | |
| 509 | + + '<input type="hidden" name="wppm_subtask_user_names[]" value="'+ui.item.user_id+'">' | |
| 510 | + +'</div>' | |
| 511 | + +'<div class="wppm_filter_display_remove" onclick="wppm_remove_subtask_user(this);"><img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/cross.svg'); ?>" alt="delete"></div>' | |
| 512 | + +'</div>' | |
| 513 | + +'</li>'; | |
| 514 | + jQuery('.wppm_subtask_filter_display_users_container').append(html_str); | |
| 515 | + jQuery(this).val(''); | |
| 516 | + return false; | |
| 517 | + } | |
| 518 | + }).focus(function(){ jQuery(this).autocomplete("search", ""); }); | |
| 519 | + }); | |
| 520 | + </script> | |
| 521 | + <?php } ?> | |
| 522 | + </div> | |
| 523 | + <?php } ?> | |
| 346 | 524 | <div class="wppm_task_checklist_container" id="wppm_task_checklist_container"> |
| 347 | 525 | <div id="wppm_checklist_container"> |
| 348 | 526 | <?php |
| 349 | 527 | if(!empty($wppm_checklist)){ |
| @@ -499,9 +677,9 @@ | ||
| 499 | 677 | absint($comment->id) |
| 500 | 678 | ) |
| 501 | 679 | ); |
| 502 | 680 | $user = get_userdata( $comment->created_by ); |
| 503 | - $comment_body = (!empty($comment->body) ? wp_kses_post(wpautop($comment->body)) : ''); | |
| 681 | + $comment_body = (!empty($comment->body) ? ($comment->body) : ''); | |
| 504 | 682 | $date = wp_date("Y-m-d H:i:s" ,strtotime($comment->create_time)); |
| 505 | 683 | $thread_date = wp_date("d F Y, h:i:s A" ,strtotime($date)); |
| 506 | 684 | $attachment_ids = isset($comment->attachment_ids)? $comment->attachment_ids : ''; |
| 507 | 685 | if($attachment_ids!=""){ |
| @@ -589,11 +767,16 @@ | ||
| 589 | 767 | </div> |
| 590 | 768 | </div> |
| 591 | 769 | <div class="wppm_thread_messege" style="color:<?php echo esc_attr($appearance_settings['comment-secondary-color']);?>"> |
| 592 | 770 | <?php |
| 593 | - $allowedtags = array( 'br' => array(), 'abbr' => array('title' => array(),), 'p' => array(), 'strong' => array(), 'a' => array('href' => array(), 'title' => array(), 'target'=> array(), 'rel'=>array()),'em' =>array(),'span' =>array(), 'blockquote'=>array('cite' => array(),),'div' => array('class' => array(),'title' => array(),'style' => array(),),'ul'=>array(),'li'=>array(),'ol'=>array(),'img' => array( 'alt'=> array(),'class' => array(),'height' => array(),'src'=> array(),'width'=> array(),)); | |
| 771 | + $allowedtags = array( 'br' => array(), 'abbr' => array('title' => array(),), 'p' => array(), 'strong' => array(), 'a' => array('href' => array(), 'title' => array(), 'target'=> array(), 'rel'=>array()),'em' =>array(),'span' =>array('class' => true, | |
| 772 | + 'data-user-id' => true,'data-username' => true,), 'blockquote'=>array('cite' => array(),),'div' => array('class' => array(),'title' => array(),'style' => array(),),'ul'=>array(),'li'=>array(),'ol'=>array(),'img' => array( 'alt'=> array(),'class' => array(),'height' => array(),'src'=> array(),'width'=> array(),)); | |
| 594 | 773 | if(!empty($comment_body) && ((empty($task_comment_meta->comment_type)) || (isset($task_comment_meta->comment_type) && $task_comment_meta->comment_type=='comment') || (isset($task_comment_meta->comment_type) && $task_comment_meta->comment_type=='delete_task_comment'))){ |
| 595 | - echo wp_kses(wpautop($comment_body),$allowedtags); | |
| 774 | + $comment_body = $wppmfunction->wppm_clean_mentions_html($comment_body); | |
| 775 | + $comment_body = $wppmfunction->wppm_highlight_user_mentions($comment_body, $current_user->ID); | |
| 776 | + //echo wp_kses(wpautop($comment_body),$allowedtags); | |
| 777 | + //wp_kses($comment, $allowed_tags); | |
| 778 | + echo wp_kses_post(($comment_body)); | |
| 596 | 779 | } elseif(!empty($comment->body) && (isset($task_comment_meta->comment_type) && $task_comment_meta->comment_type=='change_task_status')){ ?> |
| 597 | 780 | <span class="wppm_admin_label" style="margin-right: 10px; background-color:<?php echo isset($task_prev_status->bg_color) ? esc_attr($task_prev_status->bg_color):""; ?>;color:<?php echo isset($task_prev_status->color) ? esc_attr($task_prev_status->color): "" ?>;"><?php echo isset($task_prev_status->name) ? esc_attr($task_prev_status->name) : "" ?></span> <img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/arrow-right.svg'); ?>" alt="arrow_right"> <span class="wppm_admin_label" style="margin-left:10px; background-color:<?php echo isset($task_new_status->bg_color) ? esc_attr($task_new_status->bg_color):""; ?>;color:<?php echo isset($task_new_status->color) ? esc_attr($task_new_status->color): "" ?>;"><?php echo isset($task_new_status->name) ? esc_attr($task_new_status->name) : "" ?></span><?php |
| 598 | 781 | }elseif(!empty($comment->body) && (isset($task_comment_meta->comment_type) && $task_comment_meta->comment_type=='change_task_creator')){ ?> |
| 599 | 782 | <span style="margin-right: 10px;"><?php echo isset($prev_user_data->display_name) ? esc_attr($prev_user_data->display_name) : "" ?></span> <img src="<?php echo esc_url( WPPM_PLUGIN_URL . 'asset/images/arrow-right.svg'); ?>" alt="arrow_right"> <span style="margin-left:10px;"><?php echo isset($new_user_data->display_name) ? esc_attr($new_user_data->display_name) : "" ?></span><?php |
| @@ -643,8 +826,11 @@ | ||
| 643 | 826 | if(!empty($attachments)){ |
| 644 | 827 | foreach( $attachments as $attachment ): |
| 645 | 828 | $download_url = site_url('/').'?wppm_attachment='.$attachment.'&tid='.$id.'&tac='.$auth_id; |
| 646 | 829 | $attachment = absint($attachment); |
| 830 | + if (empty($attachment)) { | |
| 831 | + continue; // or return, depending on the context | |
| 832 | + } | |
| 647 | 833 | $attach = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}wppm_attachments where id=%d",$attachment)); |
| 648 | 834 | $findStr = ".txt"; |
| 649 | 835 | if(!empty( $attach)){ |
| 650 | 836 | $attachment_name = preg_replace('/' . $findStr . '/', "", $attach->name, 1); |
| @@ -790,8 +976,11 @@ | ||
| 790 | 976 | // Hide when clicking outside |
| 791 | 977 | document.addEventListener('click', () => { |
| 792 | 978 | box.style.display = 'none'; |
| 793 | 979 | }); |
| 980 | + jQuery('#wppm_task_comment').on('focus', function(){ | |
| 981 | + // showMentionList(''); | |
| 982 | + }); | |
| 794 | 983 | <?php |
| 795 | 984 | if ((($current_user->ID && $current_user->has_cap('manage_options')) || $wppmfunction->has_permission('change_task_details',$task->id))){ ?> |
| 796 | 985 | jQuery("#wppm_edit_tstart_date").flatpickr({ |
| 797 | 986 | enableTime: true, |
| @@ -854,47 +1043,59 @@ | ||
| 854 | 1043 | $italic = (isset($wppm_toolbar_actions['italic']) && $wppm_toolbar_actions['italic']==1)? 'italic' :""; |
| 855 | 1044 | $underline = (isset($wppm_toolbar_actions['underline']) && $wppm_toolbar_actions['underline']==1)?'underline' :""; |
| 856 | 1045 | $blockquote = (isset($wppm_toolbar_actions['blockquote']) && $wppm_toolbar_actions['blockquote']==1)? 'blockquote' :""; |
| 857 | 1046 | $align = (isset($wppm_toolbar_actions['align']) && $wppm_toolbar_actions['align']==1)? ' alignleft aligncenter alignright ' :""; |
| 858 | - $bullist = (isset($wppm_toolbar_actions['bullist']) && $wppm_toolbar_actions['bullist']==1)? $bullist = 'bullist' :""; | |
| 859 | - $numlist = (isset($wppm_toolbar_actions['numlist']) && $wppm_toolbar_actions['numlist']==1)? $numlist = 'numlist' :""; | |
| 860 | - $rtl = (isset($wppm_toolbar_actions['rtl']) && $wppm_toolbar_actions['rtl']==1)? $rtl = 'rtl' :""; | |
| 861 | - $link = (isset($wppm_toolbar_actions['link']) && $wppm_toolbar_actions['link']==1)? $link = 'link' :""; | |
| 862 | - $image = (isset($wppm_toolbar_actions['wppm_insert_editor_img']) && $wppm_toolbar_actions['wppm_insert_editor_img']==1)? $image = 'image' :""; | |
| 863 | - $forecolor = (isset($wppm_toolbar_actions['forecolor']) && $wppm_toolbar_actions['forecolor']==1)? $forecolor = 'forecolor' :""; | |
| 864 | - $backcolor = (isset($wppm_toolbar_actions['backcolor']) && $wppm_toolbar_actions['backcolor']==1)? $backcolor = 'backcolor' :""; | |
| 865 | - $strikethrough = (isset($wppm_toolbar_actions['strikethrough']) && $wppm_toolbar_actions['strikethrough']==1)? $strikethrough = 'strikethrough' :""; | |
| 1047 | + $bullist = (isset($wppm_toolbar_actions['bullist']) && $wppm_toolbar_actions['bullist']==1)? 'bullist' :""; | |
| 1048 | + $numlist = (isset($wppm_toolbar_actions['numlist']) && $wppm_toolbar_actions['numlist']==1)? 'numlist' :""; | |
| 1049 | + $rtl = (isset($wppm_toolbar_actions['rtl']) && $wppm_toolbar_actions['rtl']==1)? 'rtl' :""; | |
| 1050 | + $link = (isset($wppm_toolbar_actions['link']) && $wppm_toolbar_actions['link']==1)? 'link' :""; | |
| 1051 | + $image = (isset($wppm_toolbar_actions['wppm_insert_editor_img']) && $wppm_toolbar_actions['wppm_insert_editor_img']==1)? 'image' :""; | |
| 1052 | + $forecolor = (isset($wppm_toolbar_actions['forecolor']) && $wppm_toolbar_actions['forecolor']==1)? 'forecolor' :""; | |
| 1053 | + $backcolor = (isset($wppm_toolbar_actions['backcolor']) && $wppm_toolbar_actions['backcolor']==1)? 'backcolor' :""; | |
| 1054 | + $strikethrough = (isset($wppm_toolbar_actions['strikethrough']) && $wppm_toolbar_actions['strikethrough']==1)? 'strikethrough' :""; | |
| 866 | 1055 | $toolbar = trim("$bold $italic $underline $blockquote | $align | $bullist $numlist | $rtl | $link $image | $forecolor $backcolor $strikethrough"); |
| 867 | 1056 | if(($wppm_tinymce_visibility_open_task==1)){ ?> |
| 868 | 1057 | if((wppm_admin.rich_text_editor) && (wppm_admin.rich_text_editor.trim().length > 0) && (wppm_admin.rich_text_editor == 1)){ |
| 869 | - tinymce.remove(); | |
| 870 | - tinymce.init({ | |
| 1058 | + getMentionDropdown(editor); | |
| 1059 | + tinymce.remove(); | |
| 1060 | + tinymce.init({ | |
| 871 | 1061 | selector:'#wppm_task_comment', |
| 872 | 1062 | body_id: 'wppm_task_comment', |
| 873 | - directionality : '<?php //echo 'rtl'; ?>', | |
| 874 | 1063 | menubar: false, |
| 875 | 1064 | statusbar: false, |
| 876 | 1065 | height : '200', |
| 877 | 1066 | width : '100%', |
| 878 | - plugins: [ | |
| 879 | - 'lists link image directionality paste textcolor' | |
| 880 | - ], | |
| 881 | - image_advtab: true, | |
| 882 | - toolbar:'<?php echo esc_js( $toolbar ); ?>', | |
| 883 | - branding: false, | |
| 884 | - autoresize_bottom_margin: 20, | |
| 885 | - browser_spellcheck : true, | |
| 886 | - relative_urls : false, | |
| 887 | - remove_script_host : false, | |
| 888 | - convert_urls : true, | |
| 889 | - paste_as_text: true, | |
| 1067 | + plugins: ['lists link image directionality paste textcolor'], | |
| 1068 | + valid_elements: '*[*]', | |
| 1069 | + extended_valid_elements: 'span[class|data-username|data-user-id|,p,br,strong,em,a[href|target]contenteditable]', | |
| 1070 | + toolbar:'<?php echo esc_js($toolbar); ?>', | |
| 1071 | + content_style: ` | |
| 1072 | + .wppm-mention{ | |
| 1073 | + display:inline-block; | |
| 1074 | + background:linear-gradient(135deg,#eef2ff,#e0e7ff); | |
| 1075 | + color:#5b21b6; | |
| 1076 | + padding:2px 8px; | |
| 1077 | + border-radius:16px; | |
| 1078 | + font-weight:600; | |
| 1079 | + border:1px solid #c7d2fe; | |
| 1080 | + } | |
| 1081 | + | |
| 1082 | + .wppm-mention-me{ | |
| 1083 | + background:linear-gradient(135deg,#fef3c7,#fde68a); | |
| 1084 | + color:#92400e; | |
| 1085 | + border:1px solid #fbbf24; | |
| 1086 | + font-weight:700; | |
| 1087 | + } | |
| 1088 | + ` | |
| 890 | 1089 | setup: function (editor) { |
| 1090 | + wppmmenwppmMentionSetup(editor) | |
| 1091 | + | |
| 1092 | + } // ✅ only ONE setup | |
| 1093 | + }); | |
| 1094 | + jQuery('#wppm_comment_btn').show(); | |
| 891 | 1095 | } |
| 892 | - }); | |
| 893 | - jQuery('#wppm_comment_btn').show(); | |
| 894 | - } | |
| 895 | - <?php } ?> | |
| 896 | -}); | |
| 1096 | + <?php } ?> | |
| 1097 | + }); | |
| 897 | 1098 | |
| 898 | 1099 | jQuery(function(jQuery){ |
| 899 | 1100 | // Checklist Sorting |
| 900 | 1101 | jQuery(".wppm_checklist_items_container").sortable({ |
| @@ -969,8 +1170,9 @@ | ||
| 969 | 1170 | remove_script_host : false, |
| 970 | 1171 | convert_urls : true, |
| 971 | 1172 | paste_as_text: true, |
| 972 | 1173 | setup: function (editor) { |
| 1174 | + wppmMentionSetup(editor); | |
| 973 | 1175 | } |
| 974 | 1176 | }); |
| 975 | 1177 | } else{ |
| 976 | 1178 | jQuery('#wppm_task_comment').css("width", "100%"); |
| @@ -979,18 +1181,30 @@ | ||
| 979 | 1181 | } |
| 980 | 1182 | jQuery('#wppm_comment_btn').show(); |
| 981 | 1183 | } |
| 982 | 1184 | |
| 983 | -function wppm_submit_task_comment(id,proj_id){ | |
| 1185 | +function wppm_submit_task_comment(id, proj_id){ | |
| 1186 | + jQuery('#wppm_mention_list').remove(); | |
| 984 | 1187 | var dataform = new FormData(jQuery('#wppm_open_task')[0]); |
| 985 | 1188 | dataform.append('action','wppm_submit_task_comment'); |
| 986 | - if((wppm_admin.rich_text_editor == 1)){ | |
| 987 | - var comment_body = tinyMCE.get('wppm_task_comment').getContent().trim(); | |
| 988 | - } else{ | |
| 989 | - var comment_body = jQuery("#wppm_task_comment").val(); | |
| 1189 | + let comment_body; | |
| 1190 | + if(wppm_admin.rich_text_editor == 1){ | |
| 1191 | + const editor = tinyMCE.get('wppm_task_comment'); | |
| 1192 | + // Remove dropdown from TinyMCE iframe | |
| 1193 | + const dropdown = editor.getDoc().getElementById('wppm_mention_list'); | |
| 1194 | + if (dropdown) { | |
| 1195 | + dropdown.remove(); | |
| 1196 | + } | |
| 1197 | + comment_body = editor.getContent().trim(); | |
| 1198 | + //comment_body = tinyMCE.get('wppm_task_comment').getContent().trim(); | |
| 1199 | + // remove mention dropdown if accidentally inserted | |
| 1200 | + //comment_body = comment_body.replace(/<div[^>]*id="wppm_mention_list"[^>]*>.*?<\/div>/gi, ''); | |
| 1201 | + comment_body = comment_body.replace( /<div class="mention-item"[\s\S]*?<\/div>/g, ''); | |
| 1202 | + } else { | |
| 1203 | + comment_body = jQuery("#wppm_task_comment").val(); | |
| 990 | 1204 | } |
| 991 | - dataform.append('comment_body',comment_body); | |
| 992 | - dataform.append('task_id',id); | |
| 1205 | + dataform.append('comment_body', comment_body); | |
| 1206 | + dataform.append('task_id', id); | |
| 993 | 1207 | jQuery('#wppm_task_container').html(wppm_admin.loading_html); |
| 994 | 1208 | jQuery.ajax({ |
| 995 | 1209 | url: wppm_admin.ajax_url, |
| 996 | 1210 | type: 'POST', |
| @@ -997,12 +1211,12 @@ | ||
| 997 | 1211 | data: dataform, |
| 998 | 1212 | processData: false, |
| 999 | 1213 | contentType: false |
| 1000 | 1214 | }) |
| 1001 | - .done(function (response_str) { | |
| 1002 | - if((proj_id!=0)||(proj_id!="")){ | |
| 1003 | - wppm_open_project_tasks(id,proj_id); | |
| 1004 | - }else if((proj_id==0)||(proj_id=="")){ | |
| 1215 | + .done(function () { | |
| 1216 | + if (proj_id != 0 && proj_id != "") { | |
| 1217 | + wppm_open_project_tasks(id, proj_id); | |
| 1218 | + } else { | |
| 1005 | 1219 | wppm_open_task(id); |
| 1006 | 1220 | } |
| 1007 | 1221 | }); |
| 1008 | 1222 | } |
| @@ -1098,6 +1312,227 @@ | ||
| 1098 | 1312 | }); |
| 1099 | 1313 | } |
| 1100 | 1314 | }); |
| 1101 | 1315 | jQuery('#wppm_attachment_upload').trigger('click'); |
| 1316 | +} | |
| 1317 | + | |
| 1318 | +function wppmMentionSetup(editor) { | |
| 1319 | + let mentionIndex = -1; | |
| 1320 | + editor.on('keyup', function (e) { | |
| 1321 | + editor.lastMentionRange = editor.selection.getRng(); | |
| 1322 | + let rng = editor.selection.getRng(); | |
| 1323 | + let node = rng.startContainer; | |
| 1324 | + | |
| 1325 | + if (!node || node.nodeType !== 3) return; | |
| 1326 | + | |
| 1327 | + let text = node.textContent; | |
| 1328 | + let cursorPos = rng.startOffset; | |
| 1329 | + let textBeforeCursor = text.substring(0, cursorPos); | |
| 1330 | + | |
| 1331 | + let match = textBeforeCursor.match(/@(\w*)$/); | |
| 1332 | + let dropdown = getMentionDropdown(editor); | |
| 1333 | + | |
| 1334 | + if (match) { | |
| 1335 | + let query = match[1]; | |
| 1336 | + let rect = rng.getBoundingClientRect(); | |
| 1337 | + if (!rect || rect.top === 0) { | |
| 1338 | + rect = editor.selection.getNode().getBoundingClientRect(); | |
| 1339 | + } | |
| 1340 | + let top = rect.bottom + editor.getWin().scrollY; | |
| 1341 | + let left = rect.left + editor.getWin().scrollX; | |
| 1342 | + jQuery.post(wppm_admin.ajax_url, { | |
| 1343 | + action: 'wppm_filter_autocomplete', | |
| 1344 | + term: query, | |
| 1345 | + field : 'task_user_name', | |
| 1346 | + task_id:<?php echo esc_attr($task_id) ?>, | |
| 1347 | + proj_id:<?php echo esc_attr($proj_id) ?> | |
| 1348 | + }, function (res) { | |
| 1349 | + | |
| 1350 | + if (typeof res === "string") res = JSON.parse(res); | |
| 1351 | + if (res.success) res = res.data; | |
| 1352 | + | |
| 1353 | + if (!Array.isArray(res)) return; | |
| 1354 | + | |
| 1355 | + dropdown.empty(); | |
| 1356 | + if( res.length === 0 ){ | |
| 1357 | + dropdown.hide(); | |
| 1358 | + return; | |
| 1359 | + }else{ | |
| 1360 | + res.forEach(user => { | |
| 1361 | + let item = jQuery('<div>') | |
| 1362 | + .addClass('mention-item') | |
| 1363 | + .attr('data-username', user.label) | |
| 1364 | + .attr('data-user-id', user.user_id) | |
| 1365 | + .text(user.label) | |
| 1366 | + .css({ | |
| 1367 | + padding: '8px 12px', | |
| 1368 | + cursor: 'pointer', | |
| 1369 | + fontSize: '14px', | |
| 1370 | + color: '#333', | |
| 1371 | + background: '#fff', | |
| 1372 | + borderBottom: '1px solid #eee' | |
| 1373 | + }); | |
| 1374 | + | |
| 1375 | + item.on('mouseenter', function () { | |
| 1376 | + jQuery(this).css({ | |
| 1377 | + background: '#0073aa', | |
| 1378 | + color: '#fff' | |
| 1379 | + }); | |
| 1380 | + }); | |
| 1381 | + item.on('mouseleave', function () { | |
| 1382 | + if (!jQuery(this).hasClass('active')) { | |
| 1383 | + jQuery(this).css({ | |
| 1384 | + background: '#fff', | |
| 1385 | + color: '#333' | |
| 1386 | + }); | |
| 1387 | + } | |
| 1388 | + }); | |
| 1389 | + dropdown.append(item); | |
| 1390 | + }); | |
| 1391 | + let items = dropdown.find('.mention-item'); | |
| 1392 | + items.removeClass('active').css({ | |
| 1393 | + background: '#fff', | |
| 1394 | + color: '#333' | |
| 1395 | + }); | |
| 1396 | + items.eq(0) | |
| 1397 | + .addClass('active') | |
| 1398 | + .css({ | |
| 1399 | + background: '#0073aa', | |
| 1400 | + color: '#fff' | |
| 1401 | + }); | |
| 1402 | + mentionIndex = 0; | |
| 1403 | + updateActiveItem(items.eq(0), mentionIndex); | |
| 1404 | + dropdown.css({ | |
| 1405 | + position: 'absolute', | |
| 1406 | + display: 'none', | |
| 1407 | + background: '#fff', | |
| 1408 | + border: '1px solid #ddd', | |
| 1409 | + borderRadius: '6px', | |
| 1410 | + padding: '5px 0', | |
| 1411 | + minWidth: '180px', | |
| 1412 | + maxHeight: '220px', | |
| 1413 | + overflowY: 'auto', | |
| 1414 | + boxShadow: '0 4px 10px rgba(0,0,0,.15)', | |
| 1415 | + zIndex: 999999999999999 | |
| 1416 | + }).show(); | |
| 1417 | + } | |
| 1418 | + }); | |
| 1419 | + } else { | |
| 1420 | + dropdown.hide(); | |
| 1421 | + } | |
| 1422 | + }); | |
| 1423 | + editor.on('keydown', function (e) { | |
| 1424 | + let dropdown = getMentionDropdown(editor); | |
| 1425 | + let items = dropdown.find('.mention-item'); | |
| 1426 | + | |
| 1427 | + if (!dropdown.is(':visible') || !items.length) return; | |
| 1428 | + | |
| 1429 | + // DOWN | |
| 1430 | + if (e.key === 'ArrowDown') { | |
| 1431 | + e.preventDefault(); | |
| 1432 | + mentionIndex++; | |
| 1433 | + | |
| 1434 | + if (mentionIndex >= items.length) { | |
| 1435 | + mentionIndex = 0; | |
| 1436 | + } | |
| 1437 | + updateActiveItem(items, mentionIndex); | |
| 1438 | + items.removeClass('active').css({ | |
| 1439 | + background: '#fff', | |
| 1440 | + color: '#333' | |
| 1441 | + }); | |
| 1442 | + | |
| 1443 | + items.eq(mentionIndex) | |
| 1444 | + .addClass('active') | |
| 1445 | + .css({ | |
| 1446 | + background: '#0073aa', | |
| 1447 | + color: '#fff' | |
| 1448 | + }); | |
| 1449 | + } | |
| 1450 | + | |
| 1451 | + // UP | |
| 1452 | + if (e.key === 'ArrowUp') { | |
| 1453 | + e.preventDefault(); | |
| 1454 | + mentionIndex--; | |
| 1455 | + if (mentionIndex < 0) { | |
| 1456 | + mentionIndex = items.length - 1; | |
| 1457 | + } | |
| 1458 | + updateActiveItem(items, mentionIndex); | |
| 1459 | + items.removeClass('active').css({ | |
| 1460 | + background: '#fff', | |
| 1461 | + color: '#333' | |
| 1462 | + }); | |
| 1463 | + | |
| 1464 | + items.eq(mentionIndex) | |
| 1465 | + .addClass('active') | |
| 1466 | + .css({ | |
| 1467 | + background: '#0073aa', | |
| 1468 | + color: '#fff' | |
| 1469 | + }); | |
| 1470 | + } | |
| 1471 | + // ENTER | |
| 1472 | + if (e.key === 'Enter') { | |
| 1473 | + if (mentionIndex >= 0) { | |
| 1474 | + e.preventDefault(); | |
| 1475 | + items.eq(mentionIndex).trigger('click'); | |
| 1476 | + } | |
| 1477 | + } | |
| 1478 | + // ESC | |
| 1479 | + if (e.key === 'Escape') { | |
| 1480 | + dropdown.hide(); | |
| 1481 | + mentionIndex = -1; | |
| 1482 | + } | |
| 1483 | + }); | |
| 1484 | + editor.on('click', function (e) { | |
| 1485 | + let target = jQuery(e.target); | |
| 1486 | + if (target.hasClass('mention-item')) { | |
| 1487 | + let username = target.data('username'); | |
| 1488 | + let userId = target.data('user-id'); | |
| 1489 | + | |
| 1490 | + editor.focus(); | |
| 1491 | + | |
| 1492 | + let rng = editor.lastMentionRange || editor.selection.getRng(); | |
| 1493 | + editor.selection.setRng(rng); | |
| 1494 | + | |
| 1495 | + let node = rng.startContainer; | |
| 1496 | + if (!node || node.nodeType !== 3) return; | |
| 1497 | + | |
| 1498 | + let text = node.textContent; | |
| 1499 | + let cursorPos = rng.startOffset; | |
| 1500 | + | |
| 1501 | + let lastAtIndex = text.substring(0, cursorPos).lastIndexOf('@'); | |
| 1502 | + | |
| 1503 | + if (lastAtIndex !== -1) { | |
| 1504 | + | |
| 1505 | + let range = editor.selection.getRng(); | |
| 1506 | + range.setStart(node, lastAtIndex); | |
| 1507 | + range.setEnd(node, cursorPos); | |
| 1508 | + | |
| 1509 | + editor.selection.setRng(range); | |
| 1510 | + | |
| 1511 | + editor.selection.setContent( | |
| 1512 | + '<span class="wppm-mention" contenteditable="false" data-username="' + username + '" data-user-id="' + userId + '">@' + username + '</span> ' | |
| 1513 | + ); | |
| 1514 | + } | |
| 1515 | + getMentionDropdown(editor).hide(); | |
| 1516 | + } | |
| 1517 | + }); | |
| 1518 | + | |
| 1519 | + editor.on('blur', function () { | |
| 1520 | + getMentionDropdown(editor).hide(); | |
| 1521 | + }); | |
| 1522 | + | |
| 1523 | + editor.on('init', function () { | |
| 1524 | + let body = editor.getBody(); | |
| 1525 | + if (!body) return; | |
| 1526 | + | |
| 1527 | + body.addEventListener('mousedown', function (e) { | |
| 1528 | + if (e.target.classList.contains('mention-item')) { | |
| 1529 | + e.preventDefault(); | |
| 1530 | + } | |
| 1531 | + }); | |
| 1532 | + if (!editor.mentionDropdown) { | |
| 1533 | + editor.mentionDropdown = jQuery('<div class="mention-dropdown"></div>'); | |
| 1534 | + jQuery('body').append(editor.mentionDropdown); // ✅ ONLY HERE | |
| 1535 | + } | |
| 1536 | + }); | |
| 1102 | 1537 | } |
| 1103 | 1538 | </script> |