Project

General

Profile

Defect #42966 » 0002-Replace-autocomplete-input-loading-icon-with-SVG.patch

Mizuki ISHIKAWA, 2025-07-07 06:58

View differences:

app/assets/javascripts/application-legacy.js
748 748
      source: url,
749 749
      minLength: 2,
750 750
      position: {collision: "flipfit"},
751
      search: function(){$('#'+fieldId).addClass('ajax-loading');},
752
      response: function(){$('#'+fieldId).removeClass('ajax-loading');}
751
      search: function(){showAutocompleteLoadingIcon(fieldId)},
752
      response: function(){restoreAutocompleteSearchIcon(fieldId)}
753 753
    }, options));
754 754
    $('#'+fieldId).addClass('autocomplete');
755 755
  });
756 756
}
757 757

  
758
function showAutocompleteLoadingIcon(fieldId) {
759
  const input = document.getElementById(fieldId);
760
  if (!input) return;
761

  
762
  const container = input.closest('p');
763
  if (!container) return;
764

  
765
  const svg = container.querySelector('svg.svg-search');
766
  if (!svg) return;
767

  
768
  updateSVGIcon(svg, 'loader');
769
  svg.classList.remove('svg-search');
770
  svg.classList.add('svg-loader');
771
  input.classList.add('ajax-loading');
772
}
773

  
774
function restoreAutocompleteSearchIcon(fieldId) {
775
  const input = document.getElementById(fieldId);
776
  if (!input) return;
777

  
778
  const container = input.closest('p');
779
  if (!container) return;
780

  
781
  const svg = container.querySelector('svg.svg-loader');
782
  if (!svg) return;
783

  
784
  updateSVGIcon(svg, 'search');
785
  svg.classList.remove('svg-loader');
786
  svg.classList.add('svg-search');
787
  input.classList.remove('ajax-loading');
788
}
789

  
758 790
function multipleAutocompleteField(fieldId, url, options) {
759 791
  function split(val) {
760 792
    return val.split(/,\s*/);
......
774 806
      minLength: 2,
775 807
      position: {collision: "flipfit"},
776 808
      search: function () {
777
        $('#' + fieldId).addClass('ajax-loading');
809
        showAutocompleteLoadingIcon(fieldId);
778 810
      },
779 811
      response: function () {
780
        $('#' + fieldId).removeClass('ajax-loading');
812
        restoreAutocompleteSearchIcon(fieldId);
781 813
      },
782 814
      select: function (event, ui) {
783 815
        var terms = split(this.value);
......
809 841
          type: 'get',
810 842
          data: {q: $this.val()},
811 843
          success: function(data){ if(targetId) $('#'+targetId).html(data); },
812
          beforeSend: function(){ $this.addClass('ajax-loading'); },
813
          complete: function(){ $this.removeClass('ajax-loading'); }
844
          beforeSend: function(){ showAutocompleteLoadingIcon(fieldId); },
845
          complete: function(){ restoreAutocompleteSearchIcon(fieldId); }
814 846
        });
815 847
      }
816 848
    };
app/assets/stylesheets/application.css
965 965
.total-hours span.hours-int { font-size: 120%; }
966 966

  
967 967
.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em; position: relative;}
968
#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select { width: 90%; }
968
#user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select { width: 90%; }
969
#user_login { width: calc(90% - 18px); }
969 970

  
970 971
#workflow_copy_form select { width: 200px; }
971 972
table.transitions td.enabled {background: #bfb;}
......
1199 1200
input#principal_search, input#user_search {width:90%}
1200 1201
.roles-selection label {display:inline-block; width:210px;}
1201 1202

  
1202
input.autocomplete {
1203
  background: #fff url(/search.svg) no-repeat 2px 50%; padding-left:20px !important;
1204
}
1205
input.autocomplete.ajax-loading {
1206
  background-image: url(/loading.gif);
1207
}
1208

  
1209 1203
.role-visibility {padding-left:2em;}
1210 1204

  
1211 1205
.objects-selection {
app/assets/stylesheets/rtl.css
230 230
.attachments_fields input.description {margin-left:0px; margin-right:4px;}
231 231

  
232 232
.attachments_fields input.filename {background:url(/attachment.png) no-repeat right 1px top 50%; padding-left:0px; padding-right:18px;}
233
.attachments_fields .ajax-waiting input.filename {background:url(/hourglass-empty.svg) no-repeat right top 50%;}
234
.attachments_fields .ajax-loading input.filename {background:url(/loading.gif) no-repeat right top 50%;}
235 233
.attachments_fields div.ui-progressbar {margin: 2px 8px -5px 0;}
236 234

  
237 235
a.remove-upload {background: url(/delete.png) no-repeat right 1px top 50%; padding-left:0px; padding-right:16px;}
......
247 245
table.members td.name {padding-right: 20px; padding-left:0; }
248 246
table.members td.group, table.members td.groupnonmember, table.members td.groupanonymous {background: url(/group.png) no-repeat right 50%;}
249 247

  
250
input.autocomplete {
251
  background: #fff url(/search.svg) no-repeat right 2px top 50%; padding-left:0px !important; padding-right:20px !important;
252
}
253

  
254 248
.role-visibility {padding-right:2em; padding-left:0;}
255 249

  
256 250
/***** Flash & error messages ****/
app/views/groups/_new_users_form.html.erb
1 1
<fieldset class="box">
2 2
  <legend><%= label_tag "user_search", l(:label_user_search) %></legend>
3
  <p><%= text_field_tag 'user_search', nil %></p>
3
  <p>
4
    <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
5
    <%= text_field_tag 'user_search', nil %>
6
  </p>
4 7
  <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
5 8

  
6 9
  <div id="users">
app/views/issue_relations/_form.html.erb
11 11
  </div>
12 12
<% end %>
13 13
<p><%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %>
14
<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :value => unsaved_relations_ids, :size => 10 %>
14
<span>
15
<%= l(:label_issue) %> #<%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %><%= f.text_field :issue_to_id, :value => unsaved_relations_ids, :size => 10 %>
16
</span>
15 17
<span id="predecessor_fields" style="display:none;">
16 18
<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
17 19
</span>
app/views/issues/_attributes.html.erb
63 63

  
64 64
<div class="splitcontentright">
65 65
<% if @issue.safe_attribute? 'parent_issue_id' %>
66
<p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10,
66
<p id="parent_issue">
67
  <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
68
  <%= f.text_field :parent_issue_id, :size => 9,
67 69
                                      :required => @issue.required_attribute?('parent_issue_id'),
68
                                      :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %></p>
70
                                      :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %>
71
</p>
69 72
<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript(auto_complete_issues_path(:project_id => @issue.project, :scope => Setting.cross_project_subtasks, :status => @issue.closed? ? 'c' : 'o', :issue_id => @issue.id))}')" %>
70 73
<% end %>
71 74

  
app/views/issues/bulk_edit.html.erb
146 146
<% if @safe_attributes.include?('parent_issue_id') && @project %>
147 147
<p>
148 148
  <label for='issue_parent_issue_id'><%= l(:field_parent_issue) %></label>
149
  <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10, :value => @issue_params[:parent_issue_id] %>
149
  <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
150
  <%= text_field_tag 'issue[parent_issue_id]', '', :size => 9, :value => @issue_params[:parent_issue_id] %>
150 151
  <label class="inline"><%= check_box_tag 'issue[parent_issue_id]', 'none', (@issue_params[:parent_issue_id] == 'none'), :id => nil, :data => {:disables => '#issue_parent_issue_id'} %><%= l(:button_clear) %></label>
151 152
</p>
152 153
<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => Setting.cross_project_subtasks)}')" %>
app/views/issues/destroy.html.erb
10 10
<label><%= radio_button_tag 'todo', 'nullify', false %> <%= l(:text_assign_time_entries_to_project) %></label><br />
11 11
<% end %>
12 12
<% if @project %>
13
<span>
13 14
<label><%= radio_button_tag 'todo', 'reassign', false, :onchange => 'if (this.checked) { $("#reassign_to_id").focus(); }' %> <%= l(:text_reassign_time_entries) %></label>
15
<%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
14 16
<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("#todo_reassign").attr("checked", true);' %>
17
</span>
15 18
<%= javascript_tag "observeAutocompleteField('reassign_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project)}')" %>
16 19
<% end %>
17 20
</p>
app/views/members/_new_form.html.erb
1 1
<fieldset class="box">
2 2
  <legend><%= label_tag("principal_search", l(:label_principal_search)) %></legend>
3
  <p><%= text_field_tag('principal_search', nil) %></p>
3
  <p>
4
    <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
5
    <%= text_field_tag('principal_search', nil) %>
6
  </p>
4 7
  <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %>
5 8
  <div id="principals_for_new_member">
6 9
    <%= render_principals_for_new_members(@project) %>
app/views/repositories/_related_issues.html.erb
32 32
       :remote => true,
33 33
       :method => :post,
34 34
       :id => 'new-relation-form', :style => (@issue ? '' : 'display: none;')) do |f| %>
35
  <%= l(:label_issue) %> #<%= text_field_tag 'issue_id', '', :size => 10 %>
35
  <p>
36
    <%= l(:label_issue) %> #
37
    <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
38
    <%= text_field_tag 'issue_id', '', :size => 10 %>
39
  </p>
36 40
  <%= submit_tag l(:button_add) %>
37 41
  <%= toggle_link l(:button_cancel), 'new-relation-form'%>
38 42
  <% end %>
app/views/timelog/_form.html.erb
11 11
  <% end %>
12 12

  
13 13
  <p>
14
    <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
14 15
    <%= f.text_field :issue_id, :size => 6, :required => Setting.timelog_required_fields.include?('issue_id') %>
15 16
    <span id="time_entry_issue">
16 17
      <%=  link_to_issue(@time_entry.issue) if @time_entry.issue.try(:visible?) %>
app/views/timelog/bulk_edit.html.erb
40 40
        :onchange => "updateBulkEditFrom('#{escape_javascript url_for(:action => 'bulk_edit', :format => 'js')}')" ) %>
41 41
    </p>
42 42
    <p>
43
      <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %>
43 44
      <label for="time_entry_issue_id"><%= l(:field_issue) %></label>
44 45
      <%= text_field :time_entry, :issue_id, :size => 6 %>
45 46
      <label class="inline"><%= check_box_tag 'time_entry[issue_id]', 'none', (@time_entry_params[:issue_id] == 'none'), :id => nil, :data => {:disables => '#time_entry_issue_id'} %><%= l(:button_clear) %></label>
app/views/users/_form.html.erb
6 6
<div class="splitcontentleft">
7 7
<fieldset class="box tabular">
8 8
  <legend><%=l(:label_information_plural)%></legend>
9
  <p><%= f.text_field :login, :required => true, :size => 25  %></p>
9
  <p><%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %><%= f.text_field :login, :required => true, :size => 25  %></p>
10 10
  <p><%= f.text_field :firstname, :required => true %></p>
11 11
  <p><%= f.text_field :lastname, :required => true %></p>
12 12
  <p><%= f.text_field :mail, :required => true %></p>
app/views/watchers/_new.html.erb
21 21
  <% end %>
22 22
  <%= hidden_field_tag 'project_id', @project.id if @project %>
23 23

  
24
  <p><%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
24
  <p>
25
    <%= label_tag 'user_search', l(:label_user_search) %><br>
26
    <%= sprite_icon 'search', icon_only: true, css_class: 'svg-search' %><%= text_field_tag 'user_search', nil %>
27
  </p>
25 28
  <%= javascript_tag(
26 29
        "observeSearchfield(
27 30
          'user_search',
(4-4/7)