partially fixed Github issue #12 : Read only attributes can't be edited anymore. Dynamic refresh for read only attributes when status changes

This commit is contained in:
Ilogeek 2017-09-19 11:39:51 +02:00
parent 7f5d6e6858
commit f314d1a472
4 changed files with 221 additions and 225 deletions

View File

@ -18,6 +18,8 @@ This plugin uses [FontAwesome icons](http://fontawesome.io/)
### Changelog ### Changelog
* **v 0.4.3** : partially fixed Github issue #12 : Read only attributes can't be edited anymore. Dynamic refresh for read only attributes when status changes
* **v 0.4.2** : fixed Github issue #10 : History list updated after modification
* **v 0.4.1** : fixed Github issue #7 : update status list to follow Redmine workflow * **v 0.4.1** : fixed Github issue #7 : update status list to follow Redmine workflow
* **v 0.4.0** : fixed Github issues #2, #4, #9. Edited dropdown display * **v 0.4.0** : fixed Github issues #2, #4, #9. Edited dropdown display
* **v 0.3.0** : start date, due date, ratio and estimated time fields are now dynamically editable. Translation files added (en, fr). Log added in console when AJAX fails * **v 0.3.0** : start date, due date, ratio and estimated time fields are now dynamically editable. Translation files added (en, fr). Log added in console when AJAX fails

View File

@ -19,62 +19,68 @@ $(document).on('click', function(e){
} }
}); });
/* Put new dropdown lists in the detailed info block */ function initEditFields()
if($('#statusListDropdown').length > 0) { {
var htmlCopy = $('#statusListDropdown').get(0).outerHTML; /* Put new dropdown lists in the detailed info block */
$('#statusListDropdown').remove(); if($('#statusListDropdown').length > 0) {
$('.details .attributes .status.attribute .value').html( '<span class="showValue">' + var htmlCopy = $('#statusListDropdown').get(0).outerHTML;
$('.details .attributes .status.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' + $('#statusListDropdown').remove();
htmlCopy); $('.details .attributes .status.attribute .value').html( '<span class="showValue">' +
$('.details .attributes .status.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#usersListDropdown').length > 0) {
var htmlCopy = $('#usersListDropdown').get(0).outerHTML;
$('#usersListDropdown').remove();
$('.details .attributes .assigned-to.attribute .value').html( '<span class="showValue">' +
$('.details .attributes .assigned-to.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#prioritiesListDropdown').length > 0) {
var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML;
$('#prioritiesListDropdown').remove();
$('.details .attributes .priority.attribute .value').html( '<span class="showValue">' +
$('.details .attributes .priority.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#doneRatioListDropdown').length > 0) {
var htmlCopy = $('#doneRatioListDropdown').get(0).outerHTML;
$('#doneRatioListDropdown').remove();
$('.details .attributes .progress.attribute .value').html('<span class="showValue">' +
$('.details .attributes .progress.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#EstimatedTimeInput').length > 0) {
var htmlCopy = $('#EstimatedTimeInput').get(0).outerHTML;
$('#EstimatedTimeInput').remove();
$('.details .attributes .estimated-hours.attribute .value').html('<span class="showValue">' +
$('.details .attributes .estimated-hours.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#StartDateInput').length > 0) {
var htmlCopy = $('#StartDateInput').get(0).outerHTML;
$('#StartDateInput').remove();
$('.details .attributes .start-date.attribute .value').html('<span class="showValue">' +
$('.details .attributes .start-date.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#DueDateInput').length > 0) {
var htmlCopy = $('#DueDateInput').get(0).outerHTML;
$('#DueDateInput').remove();
$('.details .attributes .due-date.attribute .value').html('<span class="showValue">' +
$('.details .attributes .due-date.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
} }
if($('#usersListDropdown').length > 0) { initEditFields();
var htmlCopy = $('#usersListDropdown').get(0).outerHTML;
$('#usersListDropdown').remove();
$('.details .attributes .assigned-to.attribute .value').html( '<span class="showValue">' +
$('.details .attributes .assigned-to.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#prioritiesListDropdown').length > 0) {
var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML;
$('#prioritiesListDropdown').remove();
$('.details .attributes .priority.attribute .value').html( '<span class="showValue">' +
$('.details .attributes .priority.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#doneRatioListDropdown').length > 0) {
var htmlCopy = $('#doneRatioListDropdown').get(0).outerHTML;
$('#doneRatioListDropdown').remove();
$('.details .attributes .progress.attribute .value').html('<span class="showValue">' +
$('.details .attributes .progress.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#EstimatedTimeInput').length > 0) {
var htmlCopy = $('#EstimatedTimeInput').get(0).outerHTML;
$('#EstimatedTimeInput').remove();
$('.details .attributes .estimated-hours.attribute .value').html('<span class="showValue">' +
$('.details .attributes .estimated-hours.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#StartDateInput').length > 0) {
var htmlCopy = $('#StartDateInput').get(0).outerHTML;
$('#StartDateInput').remove();
$('.details .attributes .start-date.attribute .value').html('<span class="showValue">' +
$('.details .attributes .start-date.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
if($('#DueDateInput').length > 0) {
var htmlCopy = $('#DueDateInput').get(0).outerHTML;
$('#DueDateInput').remove();
$('.details .attributes .due-date.attribute .value').html('<span class="showValue">' +
$('.details .attributes .due-date.attribute .value').html() + '</span> <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>' +
htmlCopy);
}
$('body.controller-issues.action-show').on('click', '.btn.close', function(e){ $('body.controller-issues.action-show').on('click', '.btn.close', function(e){
e.preventDefault(); e.preventDefault();
@ -130,13 +136,11 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
/* get result page content (updated issue detail page with new status) */ /* get result page content (updated issue detail page with new status) */
var parsed = $.parseHTML(msg); var parsed = $.parseHTML(msg);
var statusListDropdown = $(parsed).find("#statusListDropdown select"); /* we update the details block */
var prioritiesListDropdown = $(parsed).find('#prioritiesListDropdown select'); $('div.issue.details').html($(parsed).find('div.issue.details').html());
/* we update dropdown status with new one from updated page */ /* we init edit fields */
$('#statusListDropdown select').html(statusListDropdown.html()); initEditFields();
$('#issue_status_id').html(statusListDropdown.html()); initEditFieldListeners();
$('#prioritiesListDropdown select').html(prioritiesListDropdown.html());
$('#issue_priority_id').html(prioritiesListDropdown.html());
/* we update issue properties edit block */ /* we update issue properties edit block */
$('#all_attributes').html($(parsed).find('#all_attributes').html()); $('#all_attributes').html($(parsed).find('#all_attributes').html());
@ -152,34 +156,10 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
}, 2000); }, 2000);
}, 500); }, 500);
if(type == "progress") { // specific case for progress bar, we need to update the progress bar view
var progressBar = "<tbody><tr>";
var percentTodo = 100 - parseInt(field_value);
if(field_value != 0) { progressBar += "<td style='width: " + field_value + "%;' class='closed' title='" + field_value + "%'></td>"; }
if(percentTodo != 0) { progressBar += "<td style='width: " + percentTodo + "%;' class='todo'></td>"; }
progressBar += "</tr></tbody>";
$('.details .attributes .' + cssClass + '.attribute table.progress').attr('class', 'progress progress-' + field_value).html(progressBar);
$('.details .attributes .' + cssClass + ' .percent').html(field_value + "%");
} else if( type == "date") { // specific case for start date and due date, we have to update min and max date allowed
if(field_name == "start_date")
{
$('body').find('#DueDateInput input').attr('min', field_value);
} else if (field_name == "due_date")
{
$('body').find('#StartDateInput input').attr('max', field_value);
}
}
// update other fields to avoid conflict // update other fields to avoid conflict
$('#issue_lock_version').val(parseInt($('#issue_lock_version').val()) + 1 ); $('#issue_lock_version').val(parseInt($('#issue_lock_version').val()) + 1 );
$('#last_journal_id').val(parseInt($('#last_journal_id').val()) + 1 ); $('#last_journal_id').val(parseInt($('#last_journal_id').val()) + 1 );
if(type == "select")
{
$('#issue_' + field_name + ' option').removeAttr('selected').filter('[value=' + field_value + ']').prop('selected', true);
} else if (type == "input" || type == "date")
{
$('#issue_' + field_name).val(field_value);
}
}, },
error: function(xhr, msg, error) { error: function(xhr, msg, error) {
/* error and no update, info logged into console */ /* error and no update, info logged into console */
@ -200,100 +180,104 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
}; };
/* Listeners foreach attribute */ /* Listeners foreach attribute */
function initEditFieldListeners()
{
var domSelectStatus = $('body').find('#statusListDropdown select');
domSelectStatus.on('change', function(e){
issueDynamicUpdate('status_id', domSelectStatus.val(), 'select', 'status');
var domSelectStatus = $('body').find('#statusListDropdown select'); /* update the classes status from */
domSelectStatus.on('change', function(e){ $("#content > div.issue").removeClass(function (index, className) {
issueDynamicUpdate('status_id', domSelectStatus.val(), 'select', 'status'); return (className.match (/(^|\s)status-\S+/g) || []).join(' ');
}).addClass('status-' + domSelectStatus.val());
}); /* end on change domSelectStatus */
/* update the classes status from */ var domSelectPriorities = $('body').find('#prioritiesListDropdown select');
$("#content > div.issue").removeClass(function (index, className) { domSelectPriorities.on('change', function(e){
return (className.match (/(^|\s)status-\S+/g) || []).join(' '); issueDynamicUpdate('priority_id', domSelectPriorities.val(), 'select', 'priority');
}).addClass('status-' + domSelectStatus.val());
}); /* end on change domSelectStatus */
var domSelectPriorities = $('body').find('#prioritiesListDropdown select'); /* update the classes priority from */
domSelectPriorities.on('change', function(e){ $("#content > div.issue").removeClass(function (index, className) {
issueDynamicUpdate('priority_id', domSelectPriorities.val(), 'select', 'priority'); return (className.match (/(^|\s)priority-\S+/g) || []).join(' ');
}).addClass('priority-' + domSelectStatus.val());
}); /* end on change domSelectPriorities */
/* update the classes priority from */ var domSelectUsers = $('body').find('#usersListDropdown select');
$("#content > div.issue").removeClass(function (index, className) { domSelectUsers.on('change', function(e){
return (className.match (/(^|\s)priority-\S+/g) || []).join(' '); issueDynamicUpdate('assigned_to_id', domSelectUsers.val(), 'select', 'assigned-to');
}).addClass('priority-' + domSelectStatus.val()); }); /* end on change domSelectUsers */
}); /* end on change domSelectPriorities */
var domSelectUsers = $('body').find('#usersListDropdown select'); var domSelectRatio = $('body').find('#doneRatioListDropdown select');
domSelectUsers.on('change', function(e){ domSelectRatio.on('change', function(e){
issueDynamicUpdate('assigned_to_id', domSelectUsers.val(), 'select', 'assigned-to'); issueDynamicUpdate('done_ratio', domSelectRatio.val(), 'progress', 'progress');
}); /* end on change domSelectUsers */ }); /* end on change domSelectRatio */
var domSelectRatio = $('body').find('#doneRatioListDropdown select'); var domInputEstimatedTime = $('body').find('#EstimatedTimeInput input');
domSelectRatio.on('change', function(e){ $('#EstimatedTimeInput a.btn.validate').on('click', function(e)
issueDynamicUpdate('done_ratio', domSelectRatio.val(), 'progress', 'progress'); {
}); /* end on change domSelectRatio */ e.preventDefault();
$('.estimated-hours .value .error').remove();
var estimatedTime = parseFloat(domInputEstimatedTime.val());
if(estimatedTime >= 0)
{
issueDynamicUpdate('estimated_hours', estimatedTime, 'input', 'estimated-hours');
} else {
/* estimated time must be > 0 */
$('.estimated-hours .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_POSITIVE_NUMBER + '</span>');
}
return false;
});
var domInputEstimatedTime = $('body').find('#EstimatedTimeInput input'); domInputEstimatedTime.on('keyup', function(e){
$('#EstimatedTimeInput a.btn.validate').on('click', function(e) $('.details .attributes .estimated-hours.attribute .selectedValue span').html(
{ $('.details .attributes .estimated-hours.attribute .value input').val()
e.preventDefault(); );
$('.estimated-hours .value .error').remove(); if (e.keyCode == 13) {
var estimatedTime = parseFloat(domInputEstimatedTime.val()); $('#EstimatedTimeInput a.btn.validate').click();
if(estimatedTime >= 0) }
{ });/* end EstimatedTime */
issueDynamicUpdate('estimated_hours', estimatedTime, 'input', 'estimated-hours');
} else {
/* estimated time must be > 0 */
$('.estimated-hours .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_POSITIVE_NUMBER + '</span>');
}
return false;
});
domInputEstimatedTime.on('keyup', function(e){ var domInputStartDate = $('body').find('#StartDateInput input');
$('.details .attributes .estimated-hours.attribute .selectedValue span').html( $('#StartDateInput a.btn.validate').on('click', function(e)
$('.details .attributes .estimated-hours.attribute .value input').val() {
); e.preventDefault();
if (e.keyCode == 13) { $('.start-date .value .error').remove();
$('#EstimatedTimeInput a.btn.validate').click(); if(new Date(domInputStartDate.val()).getTime() <= new Date($('body').find('#DueDateInput input').val()).getTime())
} {
});/* end EstimatedTime */ issueDynamicUpdate('start_date', domInputStartDate.val(), 'date', 'start-date');
} else {
/* start date must be < due date */
$('.start-date .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_START_DATE + '</span>');
}
return false;
});
var domInputStartDate = $('body').find('#StartDateInput input'); domInputStartDate.on('keyup', function(e){
$('#StartDateInput a.btn.validate').on('click', function(e) if (e.keyCode == 13) {
{ $('#StartDateInput a.btn.validate').click();
e.preventDefault(); }
$('.start-date .value .error').remove(); });/* end StartDate */
if(new Date(domInputStartDate.val()).getTime() <= new Date($('body').find('#DueDateInput input').val()).getTime())
{
issueDynamicUpdate('start_date', domInputStartDate.val(), 'date', 'start-date');
} else {
/* start date must be < due date */
$('.start-date .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_START_DATE + '</span>');
}
return false;
});
domInputStartDate.on('keyup', function(e){ var domInputDueDate = $('body').find('#DueDateInput input');
if (e.keyCode == 13) { $('#DueDateInput a.btn.validate').on('click', function(e)
$('#StartDateInput a.btn.validate').click(); {
} e.preventDefault();
});/* end StartDate */ $('.due-date .value .error').remove();
if(new Date($('body').find('#StartDateInput input').val()).getTime() <= new Date(domInputDueDate.val()).getTime())
{
issueDynamicUpdate('due_date', domInputDueDate.val(), 'date', 'due-date');
} else {
/* start date must be < due date */
$('.due-date .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_DUE_DATE + '</span>');
}
return false;
});
var domInputDueDate = $('body').find('#DueDateInput input'); domInputDueDate.on('keyup', function(e){
$('#DueDateInput a.btn.validate').on('click', function(e) if (e.keyCode == 13) {
{ $('#DueDateInput a.btn.validate').click();
e.preventDefault(); }
$('.due-date .value .error').remove(); });/* end StartDate */
if(new Date($('body').find('#StartDateInput input').val()).getTime() <= new Date(domInputDueDate.val()).getTime()) }
{
issueDynamicUpdate('due_date', domInputDueDate.val(), 'date', 'due-date');
} else {
/* start date must be < due date */
$('.due-date .value').append('<span class="error"><i class="fa fa-exclamation-circle" aria-hidden="true"></i> ' + _TXT_ERROR_DUE_DATE + '</span>');
}
return false;
});
domInputDueDate.on('keyup', function(e){ initEditFieldListeners();
if (e.keyCode == 13) {
$('#DueDateInput a.btn.validate').click();
}
});/* end StartDate */

View File

@ -6,7 +6,7 @@ Redmine::Plugin.register :redmine_issue_dynamic_edit do
name 'Redmine Dynamic edit Issue plugin' name 'Redmine Dynamic edit Issue plugin'
author 'Hugo Zilliox' author 'Hugo Zilliox'
description 'Allows users to dynamically update issue attributes in detailed view' description 'Allows users to dynamically update issue attributes in detailed view'
version '0.4.2' version '0.4.3'
url 'https://github.com/ilogeek/redmine_issue_dynamic_edit' url 'https://github.com/ilogeek/redmine_issue_dynamic_edit'
author_url 'https://hzilliox.fr' author_url 'https://hzilliox.fr'
end end

View File

@ -22,6 +22,9 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
if (issue_id) if (issue_id)
issue = Issue.find(issue_id) issue = Issue.find(issue_id)
readOnlyAttributes = issue.read_only_attribute_names(User.current)
# o << issue.required_attribute_names(User.current).to_json
if (issue) if (issue)
if (User.current.allowed_to?(:edit_issues, project)) if (User.current.allowed_to?(:edit_issues, project))
@ -30,7 +33,7 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
# Status dropdown # Status dropdown
statuses = issue.new_statuses_allowed_to(User.current) statuses = issue.new_statuses_allowed_to(User.current)
if (!statuses.empty?) if (!statuses.empty? && !(readOnlyAttributes.include? 'status_id'))
o << "<span class='dynamicEdit' id='statusListDropdown'>" o << "<span class='dynamicEdit' id='statusListDropdown'>"
o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>" o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>"
statuses.each do |s| statuses.each do |s|
@ -45,8 +48,7 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
# Users dropdown # Users dropdown
assignables = project.assignable_users assignables = project.assignable_users
o << assignables.to_json if (!assignables.empty? && !(readOnlyAttributes.include? 'assigned_to_id'))
if (!assignables.empty?)
o << "<span class='dynamicEdit' id='usersListDropdown'>" o << "<span class='dynamicEdit' id='usersListDropdown'>"
o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>" o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>"
assignables.each do |u| assignables.each do |u|
@ -61,7 +63,7 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
# Priorities dropdown # Priorities dropdown
priorities = IssuePriority.all priorities = IssuePriority.all
if(!priorities.empty?) if(!priorities.empty? && !(readOnlyAttributes.include? 'priority_id'))
o << "<span class='dynamicEdit' id='prioritiesListDropdown'>" o << "<span class='dynamicEdit' id='prioritiesListDropdown'>"
o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>" o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>"
priorities.each do |p| priorities.each do |p|
@ -75,52 +77,60 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
end end
# %done dropdown # %done dropdown
percent = 0 if(!(readOnlyAttributes.include? 'done_ratio'))
o << "<span class='dynamicEdit' id='doneRatioListDropdown'>" percent = 0
o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>" o << "<span class='dynamicEdit' id='doneRatioListDropdown'>"
loop do o << "<select data-issue='#{issue_id}'><option disabled='disabled' selected> </option>"
if (percent == issue.done_ratio) loop do
o << "<option value='#{percent}' selected>#{percent}%</option>" if (percent == issue.done_ratio)
else o << "<option value='#{percent}' selected>#{percent}%</option>"
o << "<option value='#{percent}'>#{percent}%</option>" else
o << "<option value='#{percent}'>#{percent}%</option>"
end
percent += 10
if percent == 110
break
end end
percent += 10 end
if percent == 110 o << "</select> <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a></span>"
break
end
end end
o << "</select> <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a></span>"
# Estimated_time dropdown # Estimated_time dropdown
o << "<span class='dynamicEdit' id='EstimatedTimeInput'>" if(!(readOnlyAttributes.include? 'estimated_hours'))
o << " <input type='text' value='#{issue.estimated_hours}' size='6'/>" o << "<span class='dynamicEdit' id='EstimatedTimeInput'>"
o << "<a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>" o << " <input type='text' value='#{issue.estimated_hours}' size='6'/>"
o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>" o << "<a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>"
o << "</span>" o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>"
o << "</span>"
end
# Start date # Start date
o << "<span class='dynamicEdit' id='StartDateInput'>" if(!(readOnlyAttributes.include? 'start_date'))
o << " <input size=\"10\" value=\"#{issue.start_date}\" type=\"date\" max=\"#{issue.due_date}\">" o << "<span class='dynamicEdit' id='StartDateInput'>"
o << " <a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>" o << " <input size=\"10\" value=\"#{issue.start_date}\" type=\"date\" max=\"#{issue.due_date}\">"
o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>" o << " <a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>"
o << "</span>" o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>"
o << "<script>" o << "</span>"
o << "//<![CDATA[\n" o << "<script>"
o << " $(function() { $('#StartDateInput input').addClass('date').datepickerFallback(datepickerOptions); });\n" o << "//<![CDATA[\n"
o << "//]]>\n" o << " $(function() { $('#StartDateInput input').addClass('date').datepickerFallback(datepickerOptions); });\n"
o << "</script>" o << "//]]>\n"
o << "</script>"
end
# Due date # Due date
o << "<span class='dynamicEdit' id='DueDateInput'>" if(!(readOnlyAttributes.include? 'due_date'))
o << " <input size=\"10\" value=\"#{issue.due_date}\" type=\"date\" min=\"#{issue.start_date}\">" o << "<span class='dynamicEdit' id='DueDateInput'>"
o << " <a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>" o << " <input size=\"10\" value=\"#{issue.due_date}\" type=\"date\" min=\"#{issue.start_date}\">"
o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>" o << " <a href='#' class='btn btn-primary validate' aria-label='" + l(:ide_txt_validation_btn) + "'><i class='fa fa-check fa-fw' aria-hidden='true'></i></a>"
o << "</span>" o << " <a href='#' class='btn btn-primary close' aria-label='" + l(:ide_txt_cancel_btn) + "'><i class='fa fa-times fa-fw' aria-hidden='true'></i></a>"
o << "<script>" o << "</span>"
o << "//<![CDATA[\n" o << "<script>"
o << " $(function() { $('#DueDateInput input').addClass('date').datepickerFallback(datepickerOptions); });\n" o << "//<![CDATA[\n"
o << "//]]>\n" o << " $(function() { $('#DueDateInput input').addClass('date').datepickerFallback(datepickerOptions); });\n"
o << "</script>" o << "//]]>\n"
o << "</script>"
end
end end
end end