957 lines
36 KiB
PHP
957 lines
36 KiB
PHP
<div class="task_details" task_id="<?= $this -> task['id'];?>">
|
||
<a href="#" class="close"><i class="fa fa-times"></i></a>
|
||
<div class="title">
|
||
<a href="/tasks/task_edit/task_id=<?= $this -> task['id'];?>" class="_edit">
|
||
<i class="fa fa-pencil"></i>
|
||
</a>
|
||
<? if ( $this -> user['id'] == 1 ):?>
|
||
<a href="#" class="task-delete" task_id="<?= $this -> task['id'];?>">
|
||
<i class="fa fa-trash"></i>
|
||
</a>
|
||
<? endif;?>
|
||
<span class="task-title-wrapper">
|
||
<span class="task-id">#<?= $this -> task['id'];?></span>
|
||
<span class="task-title-view">
|
||
<span class="task-title-text"><?= $this -> task['name'];?></span>
|
||
<a href="#" class="task-title-edit-btn" title="Edytuj tytuł"><i class="fa fa-pencil"></i></a>
|
||
</span>
|
||
<span class="task-title-edit-box" style="display: none;">
|
||
<input type="text" class="task-title-input form-control" value="<?= htmlspecialchars($this -> task['name']);?>">
|
||
<a href="#" class="task-title-save" title="Zapisz"><i class="fa fa-check"></i></a>
|
||
<a href="#" class="task-title-cancel" title="Anuluj"><i class="fa fa-times"></i></a>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
<?
|
||
$checklist_count = is_array( $this -> task['actions'] ) ? count( $this -> task['actions'] ) : 0;
|
||
$comments_count = is_array( $this -> task['comments'] ) ? count( $this -> task['comments'] ) : 0;
|
||
$attachments_count = is_array( $this -> task_attachments ) ? count( $this -> task_attachments ) : 0;
|
||
?>
|
||
<?
|
||
$task_description_html = htmlspecialchars_decode( (string)$this -> task['text'] );
|
||
if ( $task_description_html !== '' )
|
||
{
|
||
$task_description_html = preg_replace( '/<(script|style|iframe|object|embed|link|meta|base|form|input|button|textarea|select)\b[^>]*>.*?<\/\1>/is', '', $task_description_html );
|
||
$task_description_html = preg_replace( '/<(script|style|iframe|object|embed|link|meta|base|form|input|button|textarea|select)\b[^>]*\/?>/is', '', $task_description_html );
|
||
$task_description_html = preg_replace( '/\son[a-z]+\s*=\s*(".*?"|\'.*?\'|[^\s>]+)/i', '', $task_description_html );
|
||
$task_description_html = preg_replace( '/<(\/?)div\b[^>]*>/i', '<br>', $task_description_html );
|
||
$task_description_html = preg_replace( '/<(\/?)span\b[^>]*>/i', '', $task_description_html );
|
||
$task_description_html = preg_replace( '/\s(style|class|id|width|height|align|valign|border|cellpadding|cellspacing)\s*=\s*(".*?"|\'.*?\'|[^\s>]+)/i', '', $task_description_html );
|
||
$task_description_html = preg_replace_callback( '/<a\b[^>]*>/i', function( $matches ) {
|
||
if ( preg_match( '/href\s*=\s*("|\')([^"\']+)\1/i', $matches[0], $href ) )
|
||
{
|
||
$url = trim( $href[2] );
|
||
if ( preg_match( '/^(https?:|mailto:|\/|#)/i', $url ) )
|
||
return '<a href="' . htmlspecialchars( $url, ENT_QUOTES ) . '" target="_blank" rel="noopener noreferrer">';
|
||
}
|
||
return '<a>';
|
||
}, $task_description_html );
|
||
$task_description_html = preg_replace_callback( '/<img\b[^>]*>/i', function( $matches ) {
|
||
$attrs = [];
|
||
if ( preg_match( '/src\s*=\s*("|\')([^"\']+)\1/i', $matches[0], $src ) )
|
||
{
|
||
$img_src = trim( $src[2] );
|
||
if ( preg_match( '/^(https?:|\/|data:image\/)/i', $img_src ) )
|
||
$attrs[] = 'src="' . htmlspecialchars( $img_src, ENT_QUOTES ) . '"';
|
||
}
|
||
|
||
if ( preg_match( '/alt\s*=\s*("|\')([^"\']*)\1/i', $matches[0], $alt ) )
|
||
$attrs[] = 'alt="' . htmlspecialchars( $alt[2], ENT_QUOTES ) . '"';
|
||
|
||
if ( empty( $attrs ) )
|
||
return '';
|
||
|
||
return '<img ' . implode( ' ', $attrs ) . '>';
|
||
}, $task_description_html );
|
||
$task_description_html = strip_tags( $task_description_html, '<p><br><b><strong><i><em><u><s><ul><ol><li><a><img><blockquote><pre><code><h1><h2><h3><h4><h5><h6><hr>' );
|
||
$task_description_html = preg_replace( '/(<br>\s*){3,}/i', '<br><br>', $task_description_html );
|
||
}
|
||
?>
|
||
<div class="content">
|
||
<div class="left">
|
||
<div class="task-tabs-nav" role="tablist" aria-label="Przełącz zakładkę zadania">
|
||
<a href="#" class="js-task-tab-btn is-active" data-tab="description" role="tab" aria-selected="true">Opis</a>
|
||
<a href="#" class="js-task-tab-btn" data-tab="checklist" role="tab" aria-selected="false">Lista kontrolna (<?= (int)$checklist_count;?>)</a>
|
||
<a href="#" class="js-task-tab-btn" data-tab="comments" role="tab" aria-selected="false">Komentarze (<?= (int)$comments_count;?>)</a>
|
||
<a href="#" class="js-task-tab-btn" data-tab="attachments" role="tab" aria-selected="false">Załączniki (<?= (int)$attachments_count;?>)</a>
|
||
<? if ( $this -> user['id'] == 1 ):?>
|
||
<a href="#" class="js-task-tab-btn" data-tab="users" role="tab" aria-selected="false">Uczestnicy</a>
|
||
<? endif;?>
|
||
</div>
|
||
<div class="users box">
|
||
<? if ( is_array( $this -> task['users'] ) ): foreach ( $this -> task['users'] as $user_tmp_id ):?>
|
||
<? $user_tmp = \factory\Users::user_details( $user_tmp_id );?>
|
||
<div class="user">
|
||
<div class="avatar" style="background: <?= $user_tmp['color'];?>;" title="<?= $user_tmp['name'] . $user_tmp['surname'];?>"><?= $user_tmp['name'][0] . $user_tmp['surname'][0];?></div>
|
||
<?= $user_tmp['name'] . $user_tmp['surname'];?>
|
||
</div>
|
||
<? endforeach; endif;?>
|
||
</div>
|
||
|
||
<div class="task-tab-panel is-active" data-tab="description">
|
||
<div class="task-description-view">
|
||
<? if ( $this -> task['text'] ):?>
|
||
<div class="description">
|
||
<a href="#" class="fullscreen"><i class="fa fa-expand"></i></a>
|
||
<?= $task_description_html;?>
|
||
</div>
|
||
<? else:?>
|
||
<div class="description description-empty">
|
||
Brak opisu zadania.
|
||
</div>
|
||
<? endif;?>
|
||
</div>
|
||
<div class="task-description-actions">
|
||
<a href="#" class="btn btn-primary btn-sm task-popup-compact-btn js-start-edit-task-description">Edytuj</a>
|
||
</div>
|
||
<div class="task-description-editor box" style="display: none;">
|
||
<h3>Treść zadania</h3>
|
||
<textarea class="form-control task-description-input" id="task-popup-description-<?= (int)$this -> task['id'];?>" rows="5"><?= htmlspecialchars( (string)$this -> task['text'] );?></textarea>
|
||
<div class="task-description-editor-actions">
|
||
<a href="#" class="btn btn-primary btn-sm task-popup-compact-btn js-save-task-description" task_id="<?= (int)$this -> task['id'];?>">Zapisz treść</a>
|
||
<a href="#" class="btn btn-danger btn-sm task-popup-compact-btn js-cancel-edit-task-description">Anuluj</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="task-tab-panel" data-tab="checklist">
|
||
<div class="checklist">
|
||
<h3>Lista kontrolna</h3>
|
||
<div class="new_element">
|
||
<input type="text" class="form-control" placeholder="Dodaj nowy element">
|
||
<a href="#" class="add_element" task_id="<?= $this -> task['id'];?>"><i class="fa fa-plus"></i></a>
|
||
</div>
|
||
<ul>
|
||
<? foreach ( $this -> task['actions'] as $action ):?>
|
||
<li action_id="<?= $action['id'];?>">
|
||
<input type="checkbox" class="g-checkbox" value="<?= $action[ 'id' ];?>" <? if ( $action['status'] ):?>checked="checked"<? endif;?>>
|
||
<?= $action['name'];?>
|
||
<a href="#" class="point-delete" action_id="<?= $action['id'];?>">
|
||
<i class="fa fa-trash"></i>
|
||
</a>
|
||
</li>
|
||
<? endforeach;?>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="task-tab-panel" data-tab="comments">
|
||
<div class="comments">
|
||
<h3>Komentarze</h3>
|
||
<div class="new_comment">
|
||
<textarea class="form-control" placeholder="Dodaj nowy komentarz"></textarea>
|
||
<a href="#" class="add_comment" task_id="<?= $this -> task['id'];?>">Dodaj nowy komentarz</a>
|
||
</div>
|
||
<ul>
|
||
<? foreach ( $this -> task['comments'] as $comment ):?>
|
||
<li>
|
||
<a href="#" class="delete_comment" comment_id="<?= $comment['id'];?>"><i class="fa fa-trash"></i></a>
|
||
<div class="author"><?= \factory\Users::user_details( $comment['user_id'] )['name'] . ' ' . \factory\Users::user_details( $comment['user_id'] )['surname'];?></div>
|
||
<div class="date"><?= date( 'Y/m/d H:i', strtotime( $comment['date_add'] ) );?></div>
|
||
<div class="text"><?= nl2br( $comment['text'] );?></div>
|
||
</li>
|
||
<? endforeach;?>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="task-tab-panel" data-tab="attachments">
|
||
<div class="attachments box">
|
||
<h3>Załączniki</h3>
|
||
<div class="attachments_upload">
|
||
<input type="file" class="form-control attachment_file_input" name="attachments[]" multiple>
|
||
<a href="#" class="attachment-upload-btn btn btn-primary btn-sm" task_id="<?= $this -> task['id'];?>">Dodaj załączniki</a>
|
||
</div>
|
||
<ul class="attachments_list">
|
||
<? if ( is_array( $this -> task_attachments ) and count( $this -> task_attachments ) ):?>
|
||
<? foreach ( $this -> task_attachments as $attachment ):?>
|
||
<li>
|
||
<a href="<?= $attachment['url'];?>" target="_blank" rel="noopener noreferrer" class="attachment-link" download="<?= htmlspecialchars( $attachment['title_effective'] );?>">
|
||
<?= htmlspecialchars( $attachment['title_effective'] );?>
|
||
</a>
|
||
<small>(<?= $attachment['size_human'];?>)</small>
|
||
<a href="#" class="attachment-rename" attachment_id="<?= $attachment['id'];?>" title_current="<?= htmlspecialchars( $attachment['title_effective'] );?>"><i class="fa fa-pencil"></i></a>
|
||
<a href="#" class="attachment-delete" attachment_id="<?= $attachment['id'];?>"><i class="fa fa-trash"></i></a>
|
||
</li>
|
||
<? endforeach;?>
|
||
<? else:?>
|
||
<li class="attachments-empty">Brak załączników.</li>
|
||
<? endif;?>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<? if ( $this -> user['id'] == 1 ):?>
|
||
<div class="task-tab-panel" data-tab="users">
|
||
<div class="task-users-edit">
|
||
<h3>Uczestnicy</h3>
|
||
<div class="task-users-checkboxes">
|
||
<? if ( is_array( $this -> all_users ) ): foreach ( $this -> all_users as $u ):?>
|
||
<label class="task-user-label">
|
||
<input type="checkbox" class="task-user-checkbox g-checkbox" value="<?= $u['id'];?>" <? if ( is_array( $this -> task['users'] ) and in_array( $u['id'], $this -> task['users'] ) ):?>checked="checked"<? endif;?>>
|
||
<?= $u['name'] . ' ' . $u['surname'];?>
|
||
</label>
|
||
<? endforeach; endif;?>
|
||
</div>
|
||
<div class="task-users-options">
|
||
<label class="task-user-label task-status-mail-label">
|
||
<input type="checkbox" class="task-status-change-mail-checkbox g-checkbox" value="1" <? if ( (int)$this -> task['status_change_mail'] === 1 ):?>checked="checked"<? endif;?>>
|
||
Powiadom o zmianie statusu:
|
||
</label>
|
||
</div>
|
||
<a href="#" class="btn btn-primary btn-sm js-save-task-users" task_id="<?= $this -> task['id'];?>" style="margin-top: 10px;">Zapisz</a>
|
||
</div>
|
||
</div>
|
||
<? endif;?>
|
||
</div>
|
||
<div class="right">
|
||
<div class="status box">
|
||
<h3>Status</h3>
|
||
<div class="current_status">
|
||
<select name="task_status" class="form-control" task_id="<?= $this -> task['id'];?>">
|
||
<? foreach ( \factory\Tasks::get_statuses() as $key => $status ):?>
|
||
<option value="<?= $key;?>" <? if ( $this -> task['status'] == $key ):?>selected="selected"<? endif;?>><?= $status;?></option>
|
||
<? endforeach;?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="priority box">
|
||
<h3>Priorytet</h3>
|
||
<div class="current_priority">
|
||
<select name="task_priority" class="form-control" task_id="<?= $this -> task['id'];?>">
|
||
<? foreach ( \factory\Tasks::get_priorities() as $key => $priority ):?>
|
||
<option value="<?= $key;?>" <? if ( $this -> task['priority'] == $key ):?>selected="selected"<? endif;?>><?= $priority;?></option>
|
||
<? endforeach;?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="project box">
|
||
<h3>Projekt</h3>
|
||
<div class="current_project">
|
||
<select name="task_project" class="form-control" task_id="<?= $this -> task['id'];?>">
|
||
<option value="0">-- brak --</option>
|
||
<? foreach ( $this -> projects as $project ):?>
|
||
<option value="<?= $project['id'];?>" <? if ( $this -> task['project_id'] == $project['id'] ):?>selected="selected"<? endif;?>><?= $project['name'];?></option>
|
||
<? endforeach;?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="dates box">
|
||
<h3>Termin</h3>
|
||
<div class="task-date-edit-grid">
|
||
<div class="task-date-field">
|
||
<label>Data rozpoczęcia</label>
|
||
<input type="date" class="form-control task-date-start-input" value="<?= htmlspecialchars( (string)$this -> task['date_start'] );?>">
|
||
</div>
|
||
<div class="task-date-field">
|
||
<label>Data zakończenia</label>
|
||
<input type="date" class="form-control task-date-end-input" value="<?= htmlspecialchars( (string)$this -> task['date_end'] );?>">
|
||
</div>
|
||
</div>
|
||
<a href="#" class="btn btn-primary btn-sm task-popup-compact-btn js-save-task-dates" task_id="<?= (int)$this -> task['id'];?>" style="margin-top: 10px;">Zapisz terminy</a>
|
||
</div>
|
||
<div class="client box">
|
||
<h3>Klient</h3>
|
||
<div class="current_client">
|
||
<select name="task_client" class="form-control task_client_select" task_id="<?= $this -> task['id'];?>">
|
||
<option value="0">-- brak --</option>
|
||
<? if ( is_array( $this -> clients ) ): foreach ( $this -> clients as $client ):?>
|
||
<option value="<?= (int)$client['id'];?>" <? if ( (int)$this -> task['client_id'] === (int)$client['id'] ):?>selected="selected"<? endif;?>>
|
||
<?= htmlspecialchars( $client['firm'] );?>
|
||
</option>
|
||
<? endforeach; endif;?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="time box">
|
||
<h3>Przepracowany czas</h3>
|
||
<div class="time_worked" data-total-seconds="<?= (int)$this -> task['total_time'];?>">
|
||
<a href="#" class="time_worked_toggle js-time-worked-value">
|
||
<?= sprintf( "%02d%s%02d%s%02d", floor( $this -> task['total_time'] / 3600 ), ':', ( $this -> task['total_time'] / 60) % 60, ':', $this -> task['total_time'] % 60 );?>
|
||
</a>
|
||
</div>
|
||
<a href="#" class="task_start <? if ( $this -> task['is_open'] ):?> hidden<? endif;?>" task_id="<?= $this -> task['id'];?>">
|
||
<i class="fa fa-play"></i> Włącz timer
|
||
</a>
|
||
<a href="#" class="task_end <? if ( !$this -> task['is_open'] ):?> hidden<? else:?> animate<? endif;?>" task_id="<?= $this -> task['id'];?>">
|
||
<i class="fa fa-stop"></i> Wyłącz timer
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="task_work_details">
|
||
<? foreach ( $this -> task_works as $task_work ):?>
|
||
<div class="_line">
|
||
<div class="_user"><?= \factory\Users::user_details( $task_work['user_id'] )['name'] . ' ' . \factory\Users::user_details( $task_work['user_id'] )['surname'];?></div>
|
||
<input type="text" class="form-control task_work_date_start" task_work_id="<?= $task_work['id'];?>" value="<?= $task_work['date_start'];?>"><span>-</span><input type="text" class="form-control task_work_date_end" task_work_id="<?= $task_work['id'];?>" value="<?= $task_work['date_end'];?>">
|
||
<a href="#" class="_work_delete" work_id="<?= $task_work['id'];?>" task_id="<?= $this -> task['id'];?>">
|
||
<i class="fa fa-trash"></i>
|
||
</a>
|
||
</div>
|
||
<? endforeach;?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<style type="text/css">
|
||
.task_popup .task_details .content .right .client .select2-container {
|
||
width: 100% !important;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tabs-nav {
|
||
margin: 0 0 10px 0;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
border: 1px solid #d8e2f6;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
background: #f4f8ff;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 30;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn {
|
||
padding: 8px 12px;
|
||
color: #355899;
|
||
text-decoration: none;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
border-right: 1px solid #d8e2f6;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn:last-child {
|
||
border-right: 0;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn:hover {
|
||
background: #e7f0ff;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn.is-active {
|
||
background: #6690f4;
|
||
color: #fff;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tab-panel {
|
||
margin-top: 10px;
|
||
display: none;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tab-panel.is-active {
|
||
display: block;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tab-panel .attachments {
|
||
margin-top: 0;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tab-panel .description.description-empty {
|
||
color: #6b7280;
|
||
font-style: italic;
|
||
}
|
||
|
||
.task_popup .task_details .content .left .task-tab-panel[data-tab="description"] .description:not(.description-empty) {
|
||
min-height: 320px;
|
||
max-height: calc(90vh - 300px);
|
||
overflow-y: auto;
|
||
overflow-wrap: anywhere;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection {
|
||
min-height: 35px;
|
||
border: 1px solid #cdcdcd;
|
||
border-radius: 0;
|
||
box-shadow: none;
|
||
padding: 5px 30px 5px 5px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered {
|
||
color: #4e5e6a;
|
||
padding-left: 0;
|
||
padding-right: 0;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection--single .select2-selection__arrow {
|
||
right: 8px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
}
|
||
|
||
.task_popup .task_details .content .right .client .select2-container--bootstrap-5.select2-container--focus .select2-selection,
|
||
.task_popup .task_details .content .right .client .select2-container--bootstrap-5.select2-container--open .select2-selection {
|
||
border-color: #6690f4;
|
||
}
|
||
|
||
.task_popup .task_details .task-users-checkboxes {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
.task_popup .task_details .task-user-label {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
cursor: pointer;
|
||
padding: 4px 0;
|
||
font-size: 13px;
|
||
}
|
||
.task_popup .task_details .task-user-label input[type="checkbox"] {
|
||
margin: 0;
|
||
}
|
||
.task_popup .task_details .task-users-options {
|
||
margin-top: 10px;
|
||
padding-top: 10px;
|
||
border-top: 1px solid #e6e9ed;
|
||
}
|
||
.task_popup .task_details .task-status-mail-label {
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Lightbox - powiększanie zdjęć w opisie */
|
||
.task_popup .task_details .description img {
|
||
cursor: zoom-in;
|
||
transition: opacity .2s ease;
|
||
}
|
||
.task_popup .task_details .description img:hover {
|
||
opacity: .85;
|
||
}
|
||
.task-img-lightbox {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 99999;
|
||
background: rgba(0,0,0,.85);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: zoom-out;
|
||
animation: taskLightboxIn .2s ease;
|
||
}
|
||
@keyframes taskLightboxIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
.task-img-lightbox img {
|
||
max-width: 90vw;
|
||
max-height: 90vh;
|
||
border-radius: 4px;
|
||
box-shadow: 0 0 40px rgba(0,0,0,.5);
|
||
object-fit: contain;
|
||
}
|
||
.task-img-lightbox .lightbox-close {
|
||
position: absolute;
|
||
top: 16px;
|
||
right: 24px;
|
||
color: #fff;
|
||
font-size: 32px;
|
||
cursor: pointer;
|
||
line-height: 1;
|
||
text-shadow: 0 0 8px rgba(0,0,0,.6);
|
||
}
|
||
|
||
.task_popup .task_details .title .task-title-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
flex-wrap: nowrap;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
.task_popup .task_details .title .task-title-view {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
.task_popup .task_details .title .task-title-text {
|
||
display: inline-block;
|
||
max-width: 100%;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
font-weight: 600;
|
||
}
|
||
.task_popup .task_details .title .task-title-edit-btn,
|
||
.task_popup .task_details .title .task-title-save,
|
||
.task_popup .task_details .title .task-title-cancel {
|
||
border: 1px solid #099885;
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 6px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #099885;
|
||
text-decoration: none;
|
||
flex-shrink: 0;
|
||
transition: all 0.2s ease;
|
||
}
|
||
.task_popup .task_details .title .task-title-edit-btn:hover,
|
||
.task_popup .task_details .title .task-title-save:hover,
|
||
.task_popup .task_details .title .task-title-cancel:hover {
|
||
background: #099885;
|
||
color: #fff;
|
||
}
|
||
.task_popup .task_details .title .task-title-cancel {
|
||
border-color: #cc563d;
|
||
color: #cc563d;
|
||
}
|
||
.task_popup .task_details .title .task-title-cancel:hover {
|
||
background: #cc563d;
|
||
color: #fff;
|
||
}
|
||
.task_popup .task_details .title .task-title-edit-box {
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.task_popup .task_details .title .task-title-input {
|
||
height: 36px;
|
||
border-radius: 6px;
|
||
font-size: 18px;
|
||
width: 100%;
|
||
min-width: 240px;
|
||
}
|
||
.task_popup .task_details .content .left .task-description-editor {
|
||
margin-bottom: 12px;
|
||
}
|
||
.task_popup .task_details .content .left .task-description-actions {
|
||
margin: 10px 0 12px 0;
|
||
}
|
||
.task_popup .task_details .content .left .task-description-editor .task-description-editor-actions {
|
||
margin-top: 10px;
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
.task_popup .task_details .content .left .task-description-editor .task-description-input {
|
||
min-height: 120px;
|
||
resize: vertical;
|
||
}
|
||
.task_popup .task_details .content .right .dates .task-date-edit-grid {
|
||
display: grid;
|
||
gap: 8px;
|
||
grid-template-columns: 1fr;
|
||
}
|
||
.task_popup .task_details .content .right .dates .task-date-field label {
|
||
display: block;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
color: #4e5e6a;
|
||
}
|
||
.task_popup .task_details .task-popup-compact-btn {
|
||
height: 30px;
|
||
padding: 0 10px;
|
||
font-size: 12px;
|
||
border-radius: 5px;
|
||
min-width: 0;
|
||
}
|
||
</style>
|
||
<script type="text/javascript">
|
||
( function() {
|
||
var popup = $( '.task_details[task_id="<?= $this -> task['id'];?>"]' );
|
||
if ( !popup.length )
|
||
return;
|
||
|
||
var tab_panels = popup.find( '.task-tab-panel' );
|
||
var tab_buttons = popup.find( '.js-task-tab-btn' );
|
||
var description_view = popup.find( '.task-description-view' );
|
||
var description_actions = popup.find( '.task-description-actions' );
|
||
var description_editor_box = popup.find( '.task-description-editor' );
|
||
var description_input = popup.find( '.task-description-input' );
|
||
var initial_description_text = description_input.val() || '';
|
||
var description_editor_instance = null;
|
||
var ckeditor_base_path = '/libraries/ckeditor/';
|
||
|
||
function loadScriptOnce( src ) {
|
||
var deferred = $.Deferred();
|
||
var existing_script = document.querySelector( 'script[src="' + src + '"]' );
|
||
if ( existing_script )
|
||
{
|
||
deferred.resolve();
|
||
return deferred.promise();
|
||
}
|
||
|
||
$.getScript( src )
|
||
.done( function() { deferred.resolve(); } )
|
||
.fail( function() { deferred.reject(); } );
|
||
|
||
return deferred.promise();
|
||
}
|
||
|
||
function ensureDescriptionEditorReady( callback ) {
|
||
if ( description_editor_instance || !description_input.length )
|
||
{
|
||
if ( typeof callback === 'function' )
|
||
callback();
|
||
return;
|
||
}
|
||
|
||
window.CKEDITOR_BASEPATH = ckeditor_base_path;
|
||
if ( window.CKEDITOR )
|
||
window.CKEDITOR.basePath = ckeditor_base_path;
|
||
|
||
function initEditor() {
|
||
if ( $.fn.ckeditor )
|
||
{
|
||
description_input.ckeditor({
|
||
toolbar: 'Basic',
|
||
language: 'pl',
|
||
height: '100'
|
||
});
|
||
|
||
try
|
||
{
|
||
description_editor_instance = description_input.ckeditorGet();
|
||
}
|
||
catch ( e )
|
||
{
|
||
description_editor_instance = null;
|
||
}
|
||
}
|
||
|
||
if ( typeof callback === 'function' )
|
||
callback();
|
||
}
|
||
|
||
if ( $.fn.ckeditor )
|
||
{
|
||
initEditor();
|
||
return;
|
||
}
|
||
|
||
loadScriptOnce( ckeditor_base_path + 'ckeditor.js' )
|
||
.done( function() {
|
||
if ( window.CKEDITOR )
|
||
window.CKEDITOR.basePath = ckeditor_base_path;
|
||
|
||
loadScriptOnce( ckeditor_base_path + 'adapters/jquery.js' )
|
||
.always( function() {
|
||
initEditor();
|
||
} );
|
||
} )
|
||
.fail( function() {
|
||
if ( typeof callback === 'function' )
|
||
callback();
|
||
} );
|
||
}
|
||
|
||
function getDescriptionValue() {
|
||
if ( description_editor_instance )
|
||
{
|
||
description_editor_instance.updateElement();
|
||
}
|
||
return description_input.val();
|
||
}
|
||
|
||
function setDescriptionValue( value ) {
|
||
if ( description_editor_instance )
|
||
{
|
||
description_editor_instance.setData( value || '' );
|
||
}
|
||
description_input.val( value || '' );
|
||
}
|
||
|
||
function toggleDescriptionEditMode( is_edit ) {
|
||
description_view.toggle( !is_edit );
|
||
description_actions.toggle( !is_edit );
|
||
description_editor_box.toggle( is_edit );
|
||
|
||
if ( is_edit )
|
||
{
|
||
ensureDescriptionEditorReady( function() {
|
||
if ( description_editor_instance )
|
||
description_editor_instance.focus();
|
||
else
|
||
description_input.trigger( 'focus' );
|
||
} );
|
||
}
|
||
}
|
||
|
||
function setActiveTaskTab( tab_name ) {
|
||
if ( !tab_panels.length )
|
||
return;
|
||
|
||
var allowed_tabs = [ 'description', 'checklist', 'comments', 'attachments', 'users' ];
|
||
var selected_tab = allowed_tabs.indexOf( tab_name ) >= 0 ? tab_name : 'description';
|
||
|
||
tab_panels.each( function() {
|
||
var panel = $( this );
|
||
panel.toggleClass( 'is-active', panel.attr( 'data-tab' ) === selected_tab );
|
||
});
|
||
|
||
tab_buttons.each( function() {
|
||
var button = $( this );
|
||
var is_active = button.attr( 'data-tab' ) === selected_tab;
|
||
button.toggleClass( 'is-active', is_active ).attr( 'aria-selected', is_active ? 'true' : 'false' );
|
||
});
|
||
|
||
window.crm_task_popup_active_tab = selected_tab;
|
||
}
|
||
|
||
popup.on( 'click', '.js-task-tab-btn', function( e ) {
|
||
e.preventDefault();
|
||
setActiveTaskTab( $( this ).attr( 'data-tab' ) );
|
||
} );
|
||
|
||
setActiveTaskTab( window.crm_task_popup_active_tab || 'description' );
|
||
|
||
popup.on( 'click', '.js-start-edit-task-description', function( e ) {
|
||
e.preventDefault();
|
||
toggleDescriptionEditMode( true );
|
||
} );
|
||
|
||
popup.on( 'click', '.js-cancel-edit-task-description', function( e ) {
|
||
e.preventDefault();
|
||
setDescriptionValue( initial_description_text );
|
||
toggleDescriptionEditMode( false );
|
||
} );
|
||
|
||
if ( $.fn.select2 )
|
||
{
|
||
var client_select = popup.find( '.task_client_select' );
|
||
client_select.select2({
|
||
theme: 'bootstrap-5',
|
||
width: '100%',
|
||
placeholder: 'Wybierz klienta',
|
||
dropdownParent: popup
|
||
});
|
||
|
||
client_select.on( 'select2:open', function() {
|
||
setTimeout( function() {
|
||
var search_field = document.querySelector( '.select2-container--open .select2-search__field' );
|
||
if ( search_field )
|
||
search_field.focus();
|
||
}, 0 );
|
||
} );
|
||
}
|
||
|
||
if ( $.fn.iCheck )
|
||
{
|
||
popup.find( '.task-user-checkbox, .task-status-change-mail-checkbox' ).iCheck({
|
||
checkboxClass: 'icheckbox_square-blue',
|
||
radioClass: 'iradio_square-blue'
|
||
});
|
||
}
|
||
|
||
var time_worked = popup.find( '.time_worked' );
|
||
var time_value = popup.find( '.js-time-worked-value' );
|
||
var total_seconds = parseInt( time_worked.attr( 'data-total-seconds' ), 10 ) || 0;
|
||
|
||
function formatTime( seconds ) {
|
||
seconds = parseInt( seconds, 10 ) || 0;
|
||
var h = Math.floor( seconds / 3600 );
|
||
var m = Math.floor( ( seconds % 3600 ) / 60 );
|
||
var s = seconds % 60;
|
||
return String( h ).padStart( 2, '0' ) + ':' + String( m ).padStart( 2, '0' ) + ':' + String( s ).padStart( 2, '0' );
|
||
}
|
||
|
||
function renderTime() {
|
||
time_value.text( formatTime( total_seconds ) );
|
||
time_worked.attr( 'data-total-seconds', total_seconds );
|
||
}
|
||
|
||
renderTime();
|
||
|
||
// Lightbox – kliknięcie na zdjęcie w opisie
|
||
popup.on( 'click', '.description img', function( e ) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
var src = $( this ).attr( 'src' );
|
||
if ( !src ) return;
|
||
|
||
var $overlay = $( '<div class="task-img-lightbox">' +
|
||
'<span class="lightbox-close">×</span>' +
|
||
'<img src="' + src + '">' +
|
||
'</div>' );
|
||
|
||
$( 'body' ).append( $overlay );
|
||
|
||
$overlay.on( 'click', function() {
|
||
$overlay.remove();
|
||
});
|
||
|
||
$( document ).one( 'keydown.taskLightbox', function( ev ) {
|
||
if ( ev.key === 'Escape' ) {
|
||
$overlay.remove();
|
||
}
|
||
});
|
||
});
|
||
|
||
popup.on( 'click', '.js-save-task-users', function( e ) {
|
||
e.preventDefault();
|
||
var btn = $( this );
|
||
var task_id = btn.attr( 'task_id' );
|
||
var users = [];
|
||
var status_change_mail = popup.find( '.task-status-change-mail-checkbox' ).is( ':checked' ) ? 1 : 0;
|
||
popup.find( '.task-user-checkbox:checked' ).each( function() {
|
||
users.push( $( this ).val() );
|
||
});
|
||
btn.text( 'Zapisywanie...' ).addClass( 'disabled' );
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: '/tasks/task_change_users/',
|
||
data: { task_id: task_id, users: users, status_change_mail: status_change_mail },
|
||
success: function( response ) {
|
||
var res = typeof response === 'string' ? JSON.parse( response ) : response;
|
||
if ( res.status === 'success' ) {
|
||
var names = [];
|
||
popup.find( '.task-user-checkbox:checked' ).each( function() {
|
||
names.push( $( this ).closest( '.task-user-label' ).text().trim() );
|
||
});
|
||
var html = '';
|
||
for ( var i = 0; i < names.length; i++ ) {
|
||
var initials = names[i].split( ' ' ).map( function( w ) { return w[0]; } ).join( '' );
|
||
html += '<div class="user"><div class="avatar" title="' + names[i] + '">' + initials + '</div>' + names[i] + '</div>';
|
||
}
|
||
popup.find( '.users.box' ).html( html );
|
||
if ( typeof getSelectedTaskFilters === 'function' && typeof reload_tasks === 'function' )
|
||
{
|
||
var selected_filters = getSelectedTaskFilters();
|
||
reload_tasks( selected_filters.projects, selected_filters.users );
|
||
}
|
||
btn.text( 'Zapisano!' );
|
||
} else {
|
||
btn.text( 'Błąd' );
|
||
}
|
||
setTimeout( function() { btn.text( 'Zapisz' ).removeClass( 'disabled' ); }, 1500 );
|
||
}
|
||
});
|
||
});
|
||
|
||
popup.on( 'click', '.task-title-edit-btn', function( e ) {
|
||
e.preventDefault();
|
||
popup.find( '.task-title-view' ).hide();
|
||
popup.find( '.task-title-edit-box' ).css( 'display', 'inline-flex' );
|
||
popup.find( '.task-title-input' ).focus();
|
||
});
|
||
|
||
popup.on( 'click', '.task-title-cancel', function( e ) {
|
||
e.preventDefault();
|
||
popup.find( '.task-title-edit-box' ).hide();
|
||
popup.find( '.task-title-view' ).show();
|
||
// Reset input to current text
|
||
popup.find( '.task-title-input' ).val( popup.find( '.task-title-text' ).text() );
|
||
});
|
||
|
||
popup.on( 'click', '.task-title-save', function( e ) {
|
||
e.preventDefault();
|
||
var btn = $( this );
|
||
var new_title = popup.find( '.task-title-input' ).val().trim();
|
||
var task_id = popup.attr( 'task_id' );
|
||
|
||
if ( !new_title ) return;
|
||
|
||
btn.addClass( 'disabled' );
|
||
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: '/tasks/task_change_title/',
|
||
data: { task_id: task_id, title: new_title },
|
||
success: function( response ) {
|
||
var res = typeof response === 'string' ? JSON.parse( response ) : response;
|
||
if ( res.status === 'success' ) {
|
||
popup.find( '.task-title-text' ).text( new_title );
|
||
popup.find( '.task-title-cancel' ).click(); // Close edit mode
|
||
|
||
// Update main view list if exists
|
||
if ( typeof getSelectedTaskFilters === 'function' && typeof reload_tasks === 'function' )
|
||
{
|
||
var selected_filters = getSelectedTaskFilters();
|
||
reload_tasks( selected_filters.projects, selected_filters.users );
|
||
}
|
||
} else {
|
||
alert( 'Wystąpił błąd podczas zmiany tytułu.' );
|
||
}
|
||
btn.removeClass( 'disabled' );
|
||
}
|
||
});
|
||
});
|
||
popup.on( 'keypress', '.task-title-input', function( e ) {
|
||
if ( e.which === 13 )
|
||
{
|
||
e.preventDefault();
|
||
popup.find( '.task-title-save' ).trigger( 'click' );
|
||
}
|
||
});
|
||
|
||
popup.on( 'click', '.js-save-task-dates', function( e ) {
|
||
e.preventDefault();
|
||
var btn = $( this );
|
||
var task_id = btn.attr( 'task_id' );
|
||
var date_start = popup.find( '.task-date-start-input' ).val();
|
||
var date_end = popup.find( '.task-date-end-input' ).val();
|
||
|
||
btn.text( 'Zapisywanie...' ).addClass( 'disabled' );
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: '/tasks/task_change_dates/',
|
||
data: { task_id: task_id, date_start: date_start, date_end: date_end },
|
||
success: function( response ) {
|
||
var res = typeof response === 'string' ? JSON.parse( response ) : response;
|
||
if ( res.status === 'success' )
|
||
{
|
||
btn.text( 'Zapisano!' );
|
||
if ( typeof getSelectedTaskFilters === 'function' && typeof reload_tasks === 'function' )
|
||
{
|
||
var selected_filters = getSelectedTaskFilters();
|
||
reload_tasks( selected_filters.projects, selected_filters.users );
|
||
}
|
||
}
|
||
else
|
||
btn.text( 'Błąd' );
|
||
|
||
setTimeout( function() { btn.text( 'Zapisz terminy' ).removeClass( 'disabled' ); }, 1400 );
|
||
}
|
||
} );
|
||
} );
|
||
|
||
popup.on( 'click', '.js-save-task-description', function( e ) {
|
||
e.preventDefault();
|
||
var btn = $( this );
|
||
var task_id = btn.attr( 'task_id' );
|
||
var text = getDescriptionValue();
|
||
|
||
btn.text( 'Zapisywanie...' ).addClass( 'disabled' );
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: '/tasks/task_change_text/',
|
||
data: { task_id: task_id, text: text },
|
||
success: function( response ) {
|
||
var res = typeof response === 'string' ? JSON.parse( response ) : response;
|
||
if ( res.status === 'success' )
|
||
{
|
||
btn.text( 'Zapisano!' );
|
||
initial_description_text = text;
|
||
task_popup( task_id, is_task_popup_works_time_open() );
|
||
}
|
||
else
|
||
btn.text( 'Błąd' );
|
||
|
||
setTimeout( function() { btn.text( 'Zapisz treść' ).removeClass( 'disabled' ); }, 1400 );
|
||
}
|
||
} );
|
||
} );
|
||
|
||
var interval_id = setInterval( function() {
|
||
if ( !document.body.contains( popup.get( 0 ) ) )
|
||
{
|
||
clearInterval( interval_id );
|
||
return;
|
||
}
|
||
|
||
var is_timer_running = !popup.find( '.task_end' ).hasClass( 'hidden' );
|
||
if ( is_timer_running )
|
||
{
|
||
total_seconds++;
|
||
renderTime();
|
||
}
|
||
}, 1000 );
|
||
} )();
|
||
</script>
|
||
|