From bc4cca84c9ddc2621b840bdacdff6331f119fe7a Mon Sep 17 00:00:00 2001 From: Leviscus Tempris Date: Mon, 25 Feb 2019 10:26:54 -0500 Subject: [PATCH 1/8] Fixed classes applied to issue on priority change (domSelectStatus.val() -> domSelectPriorities.val()) --- assets/javascripts/issue_dynamic_edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js index 0413c4e..a25e76f 100644 --- a/assets/javascripts/issue_dynamic_edit.js +++ b/assets/javascripts/issue_dynamic_edit.js @@ -378,7 +378,7 @@ function initEditFieldListeners() /* update the classes priority from */ $("#content > div.issue").removeClass(function (index, className) { return (className.match (/(^|\s)priority-\S+/g) || []).join(' '); - }).addClass('priority-' + domSelectStatus.val()); + }).addClass('priority-' + domSelectPriorities.val()); }); /* end on change domSelectPriorities */ var domSelectUsers = $('body').find('#usersListDropdown select'); From 9b7a698dbc9b2f4d21dcffe1f457788b832f4777 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Apr 2019 13:52:38 +0200 Subject: [PATCH 2/8] Fixed duplicate pencil on assignee (#31) --- assets/javascripts/issue_dynamic_edit.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js index a25e76f..aa34589 100644 --- a/assets/javascripts/issue_dynamic_edit.js +++ b/assets/javascripts/issue_dynamic_edit.js @@ -33,14 +33,6 @@ function initEditFields() 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(); From 58742cccfc37c093d9eff520cc81079cd7420bba Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Apr 2019 14:10:09 +0200 Subject: [PATCH 3/8] Fixed JS error on new issue page and edit page (#37) --- lib/details_issue_hooks.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/details_issue_hooks.rb b/lib/details_issue_hooks.rb index a914c78..19fdb36 100644 --- a/lib/details_issue_hooks.rb +++ b/lib/details_issue_hooks.rb @@ -5,7 +5,8 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener end def current_is_detail_page(context) - ret = context[:controller] && context[:controller].is_a?(IssuesController) && context[:request].original_url.rindex(/\/issues\/\S+/) + # check if we see an issue but not creating a new one or on the specific edit page + ret = context[:controller] && context[:controller].is_a?(IssuesController) && context[:request].original_url.rindex(/\/issues\/\S+/) && !context[:request].original_url.rindex(/\/issues\/new/) && !context[:request].original_url.rindex(/\/issues\/\d+\/edit/) end def view_layouts_base_html_head(context) From 3ef47ab625785971f9839da5e677c3c641dbeec3 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Apr 2019 14:33:35 +0200 Subject: [PATCH 4/8] Fixed specific 'middle click' issue (#36) --- assets/javascripts/issue_dynamic_edit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js index aa34589..057836a 100644 --- a/assets/javascripts/issue_dynamic_edit.js +++ b/assets/javascripts/issue_dynamic_edit.js @@ -1,4 +1,7 @@ -/* Allow inclusion from other page */ +/* + * Allow inclusion from other page + * See https://github.com/Ilogeek/redmine_issue_dynamic_edit/commit/26684a2dd9b12dcc7377afd79e9fe5c142d26ebd for more info + */ var LOCATION_HREF = typeof custom_location_href !== 'undefined' ? custom_location_href : window.location.href; /* FontAwesome inclusion */ @@ -17,6 +20,7 @@ var cssId = 'fontAwesome'; $(document).on('click', function(e){ $('.issue .attributes .attribute .value').removeClass('edited'); + if($(e.target).closest('a').length){ return; } if($(e.target).closest('.value').length) { $(e.target).closest('.value').addClass('edited'); } From 1fb2a0519c2c45ac1a584da04126fef4c6f1ebd7 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Apr 2019 23:29:20 +0200 Subject: [PATCH 5/8] Configuration file added (https settings, target and action listener choices, field exclusion) (#30 #35 #41) --- assets/javascripts/issue_dynamic_edit.js | 49 ++++++++++++++----- .../issue_dynamic_edit_configuration_file.js | 35 +++++++++++++ lib/details_issue_hooks.rb | 2 +- 3 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 assets/javascripts/issue_dynamic_edit_configuration_file.js diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js index 057836a..35d0923 100644 --- a/assets/javascripts/issue_dynamic_edit.js +++ b/assets/javascripts/issue_dynamic_edit.js @@ -1,8 +1,17 @@ +/* + * OPTIONS DEFINED FROM CONFIGURATION FILE + */ +var _CONF_FORCE_HTTPS = _CONF_FORCE_HTTPS || false; +var _CONF_LISTENER_TYPE = _CONF_LISTENER_TYPE || "click"; +var _CONF_LISTENER_TARGET = _CONF_LISTENER_TARGET || "value"; +var _CONF_EXCLUDED_FIELD_ID = _CONF_EXCLUDED_FIELD_ID || []; + /* * Allow inclusion from other page * See https://github.com/Ilogeek/redmine_issue_dynamic_edit/commit/26684a2dd9b12dcc7377afd79e9fe5c142d26ebd for more info */ var LOCATION_HREF = typeof custom_location_href !== 'undefined' ? custom_location_href : window.location.href; +if(_CONF_FORCE_HTTPS) { LOCATION_HREF = LOCATION_HREF.replace(/^http:\/\//i, 'https://'); } /* FontAwesome inclusion */ var cssId = 'fontAwesome'; @@ -18,18 +27,32 @@ var cssId = 'fontAwesome'; head.appendChild(link); } -$(document).on('click', function(e){ +$(document).on(_CONF_LISTENER_TYPE, function(e){ $('.issue .attributes .attribute .value').removeClass('edited'); if($(e.target).closest('a').length){ return; } - if($(e.target).closest('.value').length) { + if($(e.target).closest('.' + _CONF_LISTENER_TARGET).length) { + // avoid text selection if dblclick + var sel = window.getSelection ? window.getSelection() : document.selection; + if (sel) { + if (sel.removeAllRanges) { + sel.removeAllRanges(); + } else if (sel.empty) { + sel.empty(); + } + } + // we show the edit box $(e.target).closest('.value').addClass('edited'); } }); +function isExcluded(elmt_id) { + return _CONF_EXCLUDED_FIELD_ID.indexOf(elmt_id) > -1; +} + function initEditFields() { /* Put new dropdown lists in the detailed info block */ - if($('#statusListDropdown').length > 0) { + if($('#statusListDropdown').length > 0 && !isExcluded('statusListDropdown')) { var htmlCopy = $('#statusListDropdown').get(0).outerHTML; $('#statusListDropdown').remove(); $('.details .attributes .status.attribute .value').html( '' + @@ -37,7 +60,7 @@ function initEditFields() htmlCopy); } - if($('#prioritiesListDropdown').length > 0) { + if($('#prioritiesListDropdown').length > 0 && !isExcluded('prioritiesListDropdown')) { var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML; $('#prioritiesListDropdown').remove(); $('.details .attributes .priority.attribute .value').html( '' + @@ -45,7 +68,7 @@ function initEditFields() htmlCopy); } - if($('#doneRatioListDropdown').length > 0) { + if($('#doneRatioListDropdown').length > 0 && !isExcluded('doneRatioListDropdown')) { var htmlCopy = $('#doneRatioListDropdown').get(0).outerHTML; $('#doneRatioListDropdown').remove(); $('.details .attributes .progress.attribute .value').html('' + @@ -53,7 +76,7 @@ function initEditFields() htmlCopy); } - if($('#EstimatedTimeInput').length > 0) { + if($('#EstimatedTimeInput').length > 0 && !isExcluded('EstimatedTimeInput')) { var htmlCopy = $('#EstimatedTimeInput').get(0).outerHTML; $('#EstimatedTimeInput').remove(); $('.details .attributes .estimated-hours.attribute .value').html('' + @@ -61,7 +84,7 @@ function initEditFields() htmlCopy); } - if($('#StartDateInput').length > 0) { + if($('#StartDateInput').length > 0 && !isExcluded('StartDateInput')) { var htmlCopy = $('#StartDateInput').get(0).outerHTML; $('#StartDateInput').remove(); $('.details .attributes .start-date.attribute .value').html('' + @@ -69,7 +92,7 @@ function initEditFields() htmlCopy); } - if($('#DueDateInput').length > 0) { + if($('#DueDateInput').length > 0 && !isExcluded('DueDateInput')) { var htmlCopy = $('#DueDateInput').get(0).outerHTML; $('#DueDateInput').remove(); $('.details .attributes .due-date.attribute .value').html('' + @@ -77,21 +100,21 @@ function initEditFields() htmlCopy); } - if($('#TitleInput').length > 0) { + if($('#TitleInput').length > 0 && !isExcluded('TitleInput')) { var htmlCopy = $('#TitleInput').get(0).outerHTML; $('#TitleInput').remove(); $('.subject h3').html('' + $('.subject h3').html() + ' ' + htmlCopy).addClass('value'); } - if($('#DescriptionInput').length > 0) { + if($('#DescriptionInput').length > 0 && !isExcluded('DescriptionInput')) { var htmlCopy = $('#DescriptionInput').get(0).outerHTML; $('#DescriptionInput').remove(); $('div.description .wiki').html(' ' + $('div.description .wiki').html() + '' + htmlCopy).addClass('value'); } - if($('select#issue_assigned_to_id').length > 0) + if($('select#issue_assigned_to_id').length > 0 && !isExcluded('issue_assigned_to_id')) { var htmlCopy = $('select#issue_assigned_to_id').get(0).outerHTML; // 2 technics with simple or double quote (safety first) @@ -107,7 +130,7 @@ function initEditFields() editHTML); } - if($('select#issue_fixed_version_id').length > 0) + if($('select#issue_fixed_version_id').length > 0 && !isExcluded('issue_fixed_version_id')) { var htmlCopy = $('select#issue_fixed_version_id').get(0).outerHTML; // 2 technics with simple or double quote (safety first) @@ -127,7 +150,7 @@ function initEditFields() { var info = CF_VALUE_JSON[i].custom_field; var value = CF_VALUE_JSON[i].value; - if(info.visible && info.editable) + if(info.visible && info.editable && !isExcluded("issue_custom_field_values_" + info.id)) { if($('.details .attributes .cf_' + info.id + '.attribute .value').length && $('#issue_custom_field_values_' + info.id).length ) diff --git a/assets/javascripts/issue_dynamic_edit_configuration_file.js b/assets/javascripts/issue_dynamic_edit_configuration_file.js new file mode 100644 index 0000000..adec137 --- /dev/null +++ b/assets/javascripts/issue_dynamic_edit_configuration_file.js @@ -0,0 +1,35 @@ +/* + * CONFIGURATION FILE + * More info on https://github.com/Ilogeek/redmine_issue_dynamic_edit + */ + +/* + * _CONF_FORCE_HTTPS (boolean) + * Will force AJAX call performed by the plugin to be done with https protocol + * Use this value if you encounter some difficulties with "Mixed content" issues + * Allowed values : false (default), true + */ +var _CONF_FORCE_HTTPS = false; + +/* + * _CONF_LISTENER_TYPE (string) + * Choose which action will trigger the apparition of the edition block + * Allowed values : click (default), dblclick + */ +var _CONF_LISTENER_TYPE = "click"; + +/* + * _CONF_LISTENER_TARGET (string) + * Choose which area will trigger the apparition of the edition block + * "value" will target the whole line, "fa-pencil" will only target the pencil icon + * Allowed values : value (default), fa-pencil + */ +var _CONF_LISTENER_TARGET = "value"; + +/* + * _CONF_EXCLUDED_FIELD_ID (string array) + * Choose which fields to exclude. They won't have the edit block and pencil + * Custom fields have an unique ID and this ID must be prefixed by "issue_custom_field_values_". Eg : "issue_custom_field_values_4" is an allowed value + * Allowed values : array of any ID selector (css). Eg : ["statusListDropdown", "StartDateInput", "TitleInput", "issue_custom_field_values_4"] + */ +var _CONF_EXCLUDED_FIELD_ID = []; diff --git a/lib/details_issue_hooks.rb b/lib/details_issue_hooks.rb index 19fdb36..814975f 100644 --- a/lib/details_issue_hooks.rb +++ b/lib/details_issue_hooks.rb @@ -17,7 +17,7 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener def view_layouts_base_body_bottom(context) if current_is_detail_page(context) - javascript_include_tag('issue_dynamic_edit.js', :plugin => :redmine_issue_dynamic_edit) + javascript_include_tag('issue_dynamic_edit_configuration_file.js', 'issue_dynamic_edit.js', :plugin => :redmine_issue_dynamic_edit) end end From 9ab93501e5da58b03bd12cdf2af133a92729b450 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Apr 2019 23:30:03 +0200 Subject: [PATCH 6/8] v 0.6.6 update + readme --- README.md | 25 ++++++++++++++++++------- init.rb | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4db6259..3857ca7 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,43 @@ -# redmine_issue_dynamic_edit +# ✨ redmine_issue_dynamic_edit Add new elements on detailed issue page to **dynamically update issue's attributes and custom fields**, directly in the details block of the issue **without any page refresh** (*JIRA style*). ### 🔴 What info you should provide when opening an issue +>Please list your installed plugins and the Redmine version you use. Note that I can't fix every issue when you have conflict with an other plugin that also edit the page. +> >This plugin use JS a lot. Check your JS console from your web browser ( [HowTo](https://webmasters.stackexchange.com/a/77337) ) and try again to reproduce your issue. You'll see some information about what goes wrong. > >Copy and paste the result that appears in your console in the Github issue and expand all possible object (error data for example). With this data, we can look if there's a problem with the ajax call the plugin performs to update the issue or if there's any JS error. -### Example +### 🔎 Example ![Gif that represents dynamic edition of field from the detailled issue's view](/doc/edit.gif) -### Installation +### 📦 Installation * Clone repo into plugins directory : `git clone https://github.com/Ilogeek/redmine_issue_dynamic_edit.git` (be sure that the parent folder is called `redmine_issue_dynamic_edit`) * Restart your Redmine instance -### Customization +### ⚙ Configuration (new since v 0.6.6) + +You can set some settings by editing the file `assets/javascripts/issue_dynamic_edit_configuration_file.js`. Inside this file you'll find different variable : +* **\_CONF\_FORCE\_HTTPS** : Will force AJAX call performed by the plugin to be done with https protocol. Use this value if you encounter some difficulties with "Mixed content" issues +* **\_CONF\_LISTENER\_TYPE** : Choose which action will trigger the apparition of the edition block +* **\_CONF\_LISTENER\_TARGET** : Choose which area will trigger the apparition of the edition block +* **\_CONF\_EXCLUDED\_FIELD\_ID** : Choose which fields to exclude. They won't have the edit block and pencil + +### 🎨 Customization Feel free to edit `assets/stylesheets/issue_dynamic_edit.css` to update the look of your fields depending on your current Redmine Theme. This plugin uses [FontAwesome icons](http://fontawesome.io/) -### Changelog +### 🆕 Changelog -* **v.0.6.5** : Checklists plugin support (and all other plugins that compute fields when there's an issue update) (Github requests #26 and #28) + custom url support (Github request #29) -* **v.0.6.4** : version field with checkbox display is now supported, Target version and Assignee fields are also supported (Github request #24) +* **v 0.6.6** : New configuration file + Multiple fixes (#30 #31 #35 #36 #37 #38 #41) +* **v 0.6.5** : Checklists plugin support (and all other plugins that compute fields when there's an issue update) (Github requests #26 and #28) + custom url support (Github request #29) +* **v 0.6.4** : version field with checkbox display is now supported, Target version and Assignee fields are also supported (Github request #24) * **v 0.6.3** : fixed Github issue #22 : DatepickerFallback raised an error * **v 0.6.2** : fixed Github issue #22 : long description is now supported (no more 414 errors) * **v 0.6.1** : fixed Github issue #20 diff --git a/init.rb b/init.rb index 0fe2267..1eb95bb 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 without refreshing the page (JIRA style)' - version '0.6.5' + version '0.6.6' url 'https://github.com/ilogeek/redmine_issue_dynamic_edit' author_url 'https://hzilliox.fr' end From 6c53e0ef6d3bf78ceb4db4178089fbdf917e31a4 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 14 Apr 2019 23:20:54 +0200 Subject: [PATCH 7/8] Prevent datepickers to raise an error from erb file if they don't exist on the current page --- lib/details_issue_hooks.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/details_issue_hooks.rb b/lib/details_issue_hooks.rb index 814975f..9cf5fdc 100644 --- a/lib/details_issue_hooks.rb +++ b/lib/details_issue_hooks.rb @@ -131,7 +131,9 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener o << "" o << "" end @@ -145,7 +147,9 @@ class DetailsIssueHooks < Redmine::Hook::ViewListener o << "" o << "" end From 0b2ba88f71f5c7f520ade158659d797b7c62eab8 Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 24 May 2019 20:54:06 +0200 Subject: [PATCH 8/8] Text fields focus issue (#46) --- README.md | 1 + assets/javascripts/issue_dynamic_edit.js | 5 ++++- init.rb | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3857ca7..68d95fc 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ This plugin uses [FontAwesome icons](http://fontawesome.io/) ### 🆕 Changelog +* **v 0.6.7** : fixed Github issue #46 : text field focus issue * **v 0.6.6** : New configuration file + Multiple fixes (#30 #31 #35 #36 #37 #38 #41) * **v 0.6.5** : Checklists plugin support (and all other plugins that compute fields when there's an issue update) (Github requests #26 and #28) + custom url support (Github request #29) * **v 0.6.4** : version field with checkbox display is now supported, Target version and Assignee fields are also supported (Github request #24) diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js index 35d0923..57a1576 100644 --- a/assets/javascripts/issue_dynamic_edit.js +++ b/assets/javascripts/issue_dynamic_edit.js @@ -33,7 +33,10 @@ $(document).on(_CONF_LISTENER_TYPE, function(e){ if($(e.target).closest('.' + _CONF_LISTENER_TARGET).length) { // avoid text selection if dblclick var sel = window.getSelection ? window.getSelection() : document.selection; - if (sel) { + var activeElement = document.activeElement; + var inputs = ['input', 'select', 'button', 'textarea']; + + if (sel && inputs.indexOf(activeElement.tagName.toLowerCase()) === -1) { if (sel.removeAllRanges) { sel.removeAllRanges(); } else if (sel.empty) { diff --git a/init.rb b/init.rb index 1eb95bb..65af94e 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 without refreshing the page (JIRA style)' - version '0.6.6' + version '0.6.7' url 'https://github.com/ilogeek/redmine_issue_dynamic_edit' author_url 'https://hzilliox.fr' end