diff --git a/README.md b/README.md
index 102d6d4..5fc7f58 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,8 @@ This plugin uses [FontAwesome icons](http://fontawesome.io/)
### 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.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
diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js
index c463d46..179e43f 100644
--- a/assets/javascripts/issue_dynamic_edit.js
+++ b/assets/javascripts/issue_dynamic_edit.js
@@ -18,63 +18,69 @@ $(document).on('click', function(e){
$(e.target).closest('.value').addClass('edited');
}
});
-
-/* Put new dropdown lists in the detailed info block */
-if($('#statusListDropdown').length > 0) {
- var htmlCopy = $('#statusListDropdown').get(0).outerHTML;
- $('#statusListDropdown').remove();
- $('.details .attributes .status.attribute .value').html( '' +
- $('.details .attributes .status.attribute .value').html() + ' ' +
- htmlCopy);
-}
-
-if($('#usersListDropdown').length > 0) {
- var htmlCopy = $('#usersListDropdown').get(0).outerHTML;
- $('#usersListDropdown').remove();
- $('.details .attributes .assigned-to.attribute .value').html( '' +
- $('.details .attributes .assigned-to.attribute .value').html() + ' ' +
- htmlCopy);
-}
-
-if($('#prioritiesListDropdown').length > 0) {
- var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML;
- $('#prioritiesListDropdown').remove();
- $('.details .attributes .priority.attribute .value').html( '' +
- $('.details .attributes .priority.attribute .value').html() + ' ' +
- htmlCopy);
+
+function initEditFields()
+{
+ /* Put new dropdown lists in the detailed info block */
+ if($('#statusListDropdown').length > 0) {
+ var htmlCopy = $('#statusListDropdown').get(0).outerHTML;
+ $('#statusListDropdown').remove();
+ $('.details .attributes .status.attribute .value').html( '' +
+ $('.details .attributes .status.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#usersListDropdown').length > 0) {
+ var htmlCopy = $('#usersListDropdown').get(0).outerHTML;
+ $('#usersListDropdown').remove();
+ $('.details .attributes .assigned-to.attribute .value').html( '' +
+ $('.details .attributes .assigned-to.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#prioritiesListDropdown').length > 0) {
+ var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML;
+ $('#prioritiesListDropdown').remove();
+ $('.details .attributes .priority.attribute .value').html( '' +
+ $('.details .attributes .priority.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#doneRatioListDropdown').length > 0) {
+ var htmlCopy = $('#doneRatioListDropdown').get(0).outerHTML;
+ $('#doneRatioListDropdown').remove();
+ $('.details .attributes .progress.attribute .value').html('' +
+ $('.details .attributes .progress.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#EstimatedTimeInput').length > 0) {
+ var htmlCopy = $('#EstimatedTimeInput').get(0).outerHTML;
+ $('#EstimatedTimeInput').remove();
+ $('.details .attributes .estimated-hours.attribute .value').html('' +
+ $('.details .attributes .estimated-hours.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#StartDateInput').length > 0) {
+ var htmlCopy = $('#StartDateInput').get(0).outerHTML;
+ $('#StartDateInput').remove();
+ $('.details .attributes .start-date.attribute .value').html('' +
+ $('.details .attributes .start-date.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
+
+ if($('#DueDateInput').length > 0) {
+ var htmlCopy = $('#DueDateInput').get(0).outerHTML;
+ $('#DueDateInput').remove();
+ $('.details .attributes .due-date.attribute .value').html('' +
+ $('.details .attributes .due-date.attribute .value').html() + ' ' +
+ htmlCopy);
+ }
}
-if($('#doneRatioListDropdown').length > 0) {
- var htmlCopy = $('#doneRatioListDropdown').get(0).outerHTML;
- $('#doneRatioListDropdown').remove();
- $('.details .attributes .progress.attribute .value').html('' +
- $('.details .attributes .progress.attribute .value').html() + ' ' +
- htmlCopy);
-}
+initEditFields();
-if($('#EstimatedTimeInput').length > 0) {
- var htmlCopy = $('#EstimatedTimeInput').get(0).outerHTML;
- $('#EstimatedTimeInput').remove();
- $('.details .attributes .estimated-hours.attribute .value').html('' +
- $('.details .attributes .estimated-hours.attribute .value').html() + ' ' +
- htmlCopy);
-}
-
-if($('#StartDateInput').length > 0) {
- var htmlCopy = $('#StartDateInput').get(0).outerHTML;
- $('#StartDateInput').remove();
- $('.details .attributes .start-date.attribute .value').html('' +
- $('.details .attributes .start-date.attribute .value').html() + ' ' +
- htmlCopy);
-}
-
-if($('#DueDateInput').length > 0) {
- var htmlCopy = $('#DueDateInput').get(0).outerHTML;
- $('#DueDateInput').remove();
- $('.details .attributes .due-date.attribute .value').html('' +
- $('.details .attributes .due-date.attribute .value').html() + ' ' +
- htmlCopy);
-}
$('body.controller-issues.action-show').on('click', '.btn.close', function(e){
e.preventDefault();
@@ -130,14 +136,12 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
/* get result page content (updated issue detail page with new status) */
var parsed = $.parseHTML(msg);
- var statusListDropdown = $(parsed).find("#statusListDropdown select");
- var prioritiesListDropdown = $(parsed).find('#prioritiesListDropdown select');
- /* we update dropdown status with new one from updated page */
- $('#statusListDropdown select').html(statusListDropdown.html());
- $('#issue_status_id').html(statusListDropdown.html());
- $('#prioritiesListDropdown select').html(prioritiesListDropdown.html());
- $('#issue_priority_id').html(prioritiesListDropdown.html());
-
+ /* we update the details block */
+ $('div.issue.details').html($(parsed).find('div.issue.details').html());
+ /* we init edit fields */
+ initEditFields();
+ initEditFieldListeners();
+
/* we update issue properties edit block */
$('#all_attributes').html($(parsed).find('#all_attributes').html());
@@ -151,35 +155,11 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
$('.details .attributes .' + cssClass + '.attribute i.fa-check.statusOk').remove();
}, 2000);
}, 500);
-
- if(type == "progress") { // specific case for progress bar, we need to update the progress bar view
- var progressBar = "
";
- var percentTodo = 100 - parseInt(field_value);
- if(field_value != 0) { progressBar += " | "; }
- if(percentTodo != 0) { progressBar += " | "; }
- progressBar += "
";
- $('.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
$('#issue_lock_version').val(parseInt($('#issue_lock_version').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 and no update, info logged into console */
@@ -200,100 +180,104 @@ function issueDynamicUpdate(field_name, field_value, type, cssClass){
};
/* Listeners foreach attribute */
-
- var domSelectStatus = $('body').find('#statusListDropdown select');
- domSelectStatus.on('change', function(e){
- issueDynamicUpdate('status_id', domSelectStatus.val(), 'select', 'status');
+function initEditFieldListeners()
+{
+ var domSelectStatus = $('body').find('#statusListDropdown select');
+ domSelectStatus.on('change', function(e){
+ issueDynamicUpdate('status_id', domSelectStatus.val(), 'select', 'status');
- /* update the classes status from */
- $("#content > div.issue").removeClass(function (index, className) {
- return (className.match (/(^|\s)status-\S+/g) || []).join(' ');
- }).addClass('status-' + domSelectStatus.val());
- }); /* end on change domSelectStatus */
-
- var domSelectPriorities = $('body').find('#prioritiesListDropdown select');
- domSelectPriorities.on('change', function(e){
- issueDynamicUpdate('priority_id', domSelectPriorities.val(), 'select', 'priority');
+ /* update the classes status from */
+ $("#content > div.issue").removeClass(function (index, className) {
+ return (className.match (/(^|\s)status-\S+/g) || []).join(' ');
+ }).addClass('status-' + domSelectStatus.val());
+ }); /* end on change domSelectStatus */
+
+ var domSelectPriorities = $('body').find('#prioritiesListDropdown select');
+ domSelectPriorities.on('change', function(e){
+ issueDynamicUpdate('priority_id', domSelectPriorities.val(), 'select', 'priority');
- /* update the classes priority from */
- $("#content > div.issue").removeClass(function (index, className) {
- return (className.match (/(^|\s)priority-\S+/g) || []).join(' ');
- }).addClass('priority-' + domSelectStatus.val());
- }); /* end on change domSelectPriorities */
-
- var domSelectUsers = $('body').find('#usersListDropdown select');
- domSelectUsers.on('change', function(e){
- issueDynamicUpdate('assigned_to_id', domSelectUsers.val(), 'select', 'assigned-to');
- }); /* end on change domSelectUsers */
-
- var domSelectRatio = $('body').find('#doneRatioListDropdown select');
- domSelectRatio.on('change', function(e){
- issueDynamicUpdate('done_ratio', domSelectRatio.val(), 'progress', 'progress');
- }); /* end on change domSelectRatio */
-
- var domInputEstimatedTime = $('body').find('#EstimatedTimeInput input');
- $('#EstimatedTimeInput a.btn.validate').on('click', function(e)
- {
- 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(' ' + _TXT_ERROR_POSITIVE_NUMBER + '');
- }
- return false;
- });
-
- domInputEstimatedTime.on('keyup', function(e){
- $('.details .attributes .estimated-hours.attribute .selectedValue span').html(
- $('.details .attributes .estimated-hours.attribute .value input').val()
- );
- if (e.keyCode == 13) {
- $('#EstimatedTimeInput a.btn.validate').click();
- }
- });/* end EstimatedTime */
-
- var domInputStartDate = $('body').find('#StartDateInput input');
- $('#StartDateInput a.btn.validate').on('click', function(e)
- {
- e.preventDefault();
- $('.start-date .value .error').remove();
- 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(' ' + _TXT_ERROR_START_DATE + '');
- }
- return false;
- });
-
- domInputStartDate.on('keyup', function(e){
- if (e.keyCode == 13) {
- $('#StartDateInput a.btn.validate').click();
- }
- });/* end StartDate */
-
- var domInputDueDate = $('body').find('#DueDateInput input');
- $('#DueDateInput a.btn.validate').on('click', function(e)
- {
- e.preventDefault();
- $('.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(' ' + _TXT_ERROR_DUE_DATE + '');
- }
- return false;
- });
-
- domInputDueDate.on('keyup', function(e){
- if (e.keyCode == 13) {
- $('#DueDateInput a.btn.validate').click();
- }
- });/* end StartDate */
\ No newline at end of file
+ /* update the classes priority from */
+ $("#content > div.issue").removeClass(function (index, className) {
+ return (className.match (/(^|\s)priority-\S+/g) || []).join(' ');
+ }).addClass('priority-' + domSelectStatus.val());
+ }); /* end on change domSelectPriorities */
+
+ var domSelectUsers = $('body').find('#usersListDropdown select');
+ domSelectUsers.on('change', function(e){
+ issueDynamicUpdate('assigned_to_id', domSelectUsers.val(), 'select', 'assigned-to');
+ }); /* end on change domSelectUsers */
+
+ var domSelectRatio = $('body').find('#doneRatioListDropdown select');
+ domSelectRatio.on('change', function(e){
+ issueDynamicUpdate('done_ratio', domSelectRatio.val(), 'progress', 'progress');
+ }); /* end on change domSelectRatio */
+
+ var domInputEstimatedTime = $('body').find('#EstimatedTimeInput input');
+ $('#EstimatedTimeInput a.btn.validate').on('click', function(e)
+ {
+ 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(' ' + _TXT_ERROR_POSITIVE_NUMBER + '');
+ }
+ return false;
+ });
+
+ domInputEstimatedTime.on('keyup', function(e){
+ $('.details .attributes .estimated-hours.attribute .selectedValue span').html(
+ $('.details .attributes .estimated-hours.attribute .value input').val()
+ );
+ if (e.keyCode == 13) {
+ $('#EstimatedTimeInput a.btn.validate').click();
+ }
+ });/* end EstimatedTime */
+
+ var domInputStartDate = $('body').find('#StartDateInput input');
+ $('#StartDateInput a.btn.validate').on('click', function(e)
+ {
+ e.preventDefault();
+ $('.start-date .value .error').remove();
+ 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(' ' + _TXT_ERROR_START_DATE + '');
+ }
+ return false;
+ });
+
+ domInputStartDate.on('keyup', function(e){
+ if (e.keyCode == 13) {
+ $('#StartDateInput a.btn.validate').click();
+ }
+ });/* end StartDate */
+
+ var domInputDueDate = $('body').find('#DueDateInput input');
+ $('#DueDateInput a.btn.validate').on('click', function(e)
+ {
+ e.preventDefault();
+ $('.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(' ' + _TXT_ERROR_DUE_DATE + '');
+ }
+ return false;
+ });
+
+ domInputDueDate.on('keyup', function(e){
+ if (e.keyCode == 13) {
+ $('#DueDateInput a.btn.validate').click();
+ }
+ });/* end StartDate */
+}
+
+initEditFieldListeners();
\ No newline at end of file
diff --git a/init.rb b/init.rb
index ea148ff..e4d898c 100644
--- a/init.rb
+++ b/init.rb
@@ -6,7 +6,7 @@ Redmine::Plugin.register :redmine_issue_dynamic_edit do
name 'Redmine Dynamic edit Issue plugin'
author 'Hugo Zilliox'
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'
author_url 'https://hzilliox.fr'
end
diff --git a/lib/details_issue_hooks.rb b/lib/details_issue_hooks.rb
index 61891ac..5ae3b48 100644
--- a/lib/details_issue_hooks.rb
+++ b/lib/details_issue_hooks.rb
@@ -22,6 +22,9 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
if (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 (User.current.allowed_to?(:edit_issues, project))
@@ -30,7 +33,7 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener
# Status dropdown
statuses = issue.new_statuses_allowed_to(User.current)
- if (!statuses.empty?)
+ if (!statuses.empty? && !(readOnlyAttributes.include? 'status_id'))
o << ""
o << "